summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-03-18 06:07:08 +0000
committerDavid Robillard <d@drobilla.net>2007-03-18 06:07:08 +0000
commit99904735e066804358f1d0bd138a84f1e9ecda91 (patch)
tree71a924cf1660b5b00231275bd481bbd27094dd9b /libs
parenteb270e70a12c410cdd98585ad25bb6d8e384a4f5 (diff)
Merged with trunk R1612.
git-svn-id: svn://localhost/ardour2/branches/midi@1614 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/SConscript18
-rw-r--r--libs/ardour/ardour/ardour.h1
-rw-r--r--libs/ardour/ardour/audio_diskstream.h71
-rw-r--r--libs/ardour/ardour/audio_track.h1
-rw-r--r--libs/ardour/ardour/audioengine.h3
-rw-r--r--libs/ardour/ardour/audiofilesource.h56
-rw-r--r--libs/ardour/ardour/audiofilter.h1
-rw-r--r--libs/ardour/ardour/audioplaylist.h1
-rw-r--r--libs/ardour/ardour/audioregion.h1
-rw-r--r--libs/ardour/ardour/audiosource.h80
-rw-r--r--libs/ardour/ardour/auditioner.h1
-rw-r--r--libs/ardour/ardour/automation_event.h1
-rw-r--r--libs/ardour/ardour/click.h1
-rw-r--r--libs/ardour/ardour/configuration.h1
-rw-r--r--libs/ardour/ardour/configuration_variable.h5
-rw-r--r--libs/ardour/ardour/configuration_vars.h6
-rw-r--r--libs/ardour/ardour/connection.h1
-rw-r--r--libs/ardour/ardour/crossfade.h1
-rw-r--r--libs/ardour/ardour/crossfade_compare.h1
-rw-r--r--libs/ardour/ardour/curve.h1
-rw-r--r--libs/ardour/ardour/cycle_timer.h1
-rw-r--r--libs/ardour/ardour/cycles.h1
-rw-r--r--libs/ardour/ardour/dB.h1
-rw-r--r--libs/ardour/ardour/destructive_filesource.h76
-rw-r--r--libs/ardour/ardour/diskstream.h7
-rw-r--r--libs/ardour/ardour/export.h6
-rw-r--r--libs/ardour/ardour/gain.h1
-rw-r--r--libs/ardour/ardour/gdither.h1
-rw-r--r--libs/ardour/ardour/gdither_types.h1
-rw-r--r--libs/ardour/ardour/gdither_types_internal.h1
-rw-r--r--libs/ardour/ardour/insert.h1
-rw-r--r--libs/ardour/ardour/io.h4
-rw-r--r--libs/ardour/ardour/ladspa_plugin.h1
-rw-r--r--libs/ardour/ardour/location.h9
-rw-r--r--libs/ardour/ardour/logcurve.h1
-rw-r--r--libs/ardour/ardour/mix.h19
-rw-r--r--libs/ardour/ardour/named_selection.h1
-rw-r--r--libs/ardour/ardour/osc.h1
-rw-r--r--libs/ardour/ardour/panner.h1
-rw-r--r--libs/ardour/ardour/pcm_utils.h1
-rw-r--r--libs/ardour/ardour/playlist.h1
-rw-r--r--libs/ardour/ardour/playlist_templates.h1
-rw-r--r--libs/ardour/ardour/plugin.h1
-rw-r--r--libs/ardour/ardour/plugin_manager.h1
-rw-r--r--libs/ardour/ardour/port.h1
-rw-r--r--libs/ardour/ardour/redirect.h1
-rw-r--r--libs/ardour/ardour/region.h1
-rw-r--r--libs/ardour/ardour/reverse.h1
-rw-r--r--libs/ardour/ardour/route.h18
-rw-r--r--libs/ardour/ardour/route_group.h1
-rw-r--r--libs/ardour/ardour/send.h1
-rw-r--r--libs/ardour/ardour/session.h56
-rw-r--r--libs/ardour/ardour/session_connection.h1
-rw-r--r--libs/ardour/ardour/session_playlist.h1
-rw-r--r--libs/ardour/ardour/session_route.h1
-rw-r--r--libs/ardour/ardour/session_selection.h1
-rw-r--r--libs/ardour/ardour/silentfilesource.h66
-rw-r--r--libs/ardour/ardour/slave.h2
-rw-r--r--libs/ardour/ardour/sndfilesource.h7
-rw-r--r--libs/ardour/ardour/soundseq.h1
-rw-r--r--libs/ardour/ardour/source.h1
-rw-r--r--libs/ardour/ardour/source_factory.h2
-rw-r--r--libs/ardour/ardour/tempo.h1
-rw-r--r--libs/ardour/ardour/types.h8
-rw-r--r--libs/ardour/ardour/utils.h1
-rw-r--r--libs/ardour/ardour/vst_plugin.h1
-rw-r--r--libs/ardour/audio_diskstream.cc630
-rw-r--r--libs/ardour/audio_playlist.cc3
-rw-r--r--libs/ardour/audio_track.cc16
-rw-r--r--libs/ardour/audioengine.cc26
-rw-r--r--libs/ardour/audiofilesource.cc131
-rw-r--r--libs/ardour/audiofilter.cc2
-rw-r--r--libs/ardour/audioregion.cc12
-rw-r--r--libs/ardour/audiosource.cc575
-rw-r--r--libs/ardour/auditioner.cc13
-rw-r--r--libs/ardour/automation_event.cc1
-rw-r--r--libs/ardour/buffer.cc12
-rw-r--r--libs/ardour/configuration.cc19
-rw-r--r--libs/ardour/connection.cc1
-rw-r--r--libs/ardour/control_protocol_manager.cc13
-rw-r--r--libs/ardour/crossfade.cc1
-rw-r--r--libs/ardour/curve.cc1
-rw-r--r--libs/ardour/cycle_timer.cc1
-rw-r--r--libs/ardour/default_click.cc1
-rw-r--r--libs/ardour/destructive_filesource.cc424
-rw-r--r--libs/ardour/diskstream.cc5
-rw-r--r--libs/ardour/enums.cc6
-rw-r--r--libs/ardour/gain.cc1
-rw-r--r--libs/ardour/gdither.cc1
-rw-r--r--libs/ardour/globals.cc8
-rw-r--r--libs/ardour/import.cc269
-rw-r--r--libs/ardour/insert.cc1
-rw-r--r--libs/ardour/io.cc7
-rw-r--r--libs/ardour/jack_slave.cc1
-rw-r--r--libs/ardour/ladspa_plugin.cc1
-rw-r--r--libs/ardour/location.cc21
-rw-r--r--libs/ardour/macosx/English.lproj/InfoPlist.stringsbin0 -> 142 bytes
-rw-r--r--libs/ardour/macosx/Info.plist26
-rw-r--r--libs/ardour/macosx/ardour.xcodeproj/project.pbxproj1214
-rw-r--r--libs/ardour/macosx/ardour_Prefix.pch4
-rw-r--r--libs/ardour/macosx/version.cc3
-rw-r--r--libs/ardour/macosx/version.h17
-rw-r--r--libs/ardour/midi_diskstream.cc1
-rw-r--r--libs/ardour/mix.cc28
-rw-r--r--libs/ardour/mtc_slave.cc38
-rw-r--r--libs/ardour/named_selection.cc1
-rw-r--r--libs/ardour/osc.cc18
-rw-r--r--libs/ardour/panner.cc1
-rw-r--r--libs/ardour/pcm_utils.cc1
-rw-r--r--libs/ardour/playlist.cc33
-rw-r--r--libs/ardour/playlist_factory.cc1
-rw-r--r--libs/ardour/plugin.cc1
-rw-r--r--libs/ardour/plugin_manager.cc1
-rw-r--r--libs/ardour/port.cc1
-rw-r--r--libs/ardour/redirect.cc1
-rw-r--r--libs/ardour/region.cc7
-rw-r--r--libs/ardour/region_factory.cc1
-rw-r--r--libs/ardour/reverse.cc33
-rw-r--r--libs/ardour/route.cc48
-rw-r--r--libs/ardour/route_group.cc1
-rw-r--r--libs/ardour/send.cc1
-rw-r--r--libs/ardour/session.cc164
-rw-r--r--libs/ardour/session_butler.cc11
-rw-r--r--libs/ardour/session_click.cc1
-rw-r--r--libs/ardour/session_command.cc5
-rw-r--r--libs/ardour/session_control.cc30
-rw-r--r--libs/ardour/session_events.cc1
-rw-r--r--libs/ardour/session_export.cc58
-rw-r--r--libs/ardour/session_feedback.cc1
-rw-r--r--libs/ardour/session_midi.cc110
-rw-r--r--libs/ardour/session_process.cc29
-rw-r--r--libs/ardour/session_state.cc153
-rw-r--r--libs/ardour/session_time.cc1
-rw-r--r--libs/ardour/session_timefx.cc46
-rw-r--r--libs/ardour/session_transport.cc15
-rw-r--r--libs/ardour/session_vst.cc1
-rw-r--r--libs/ardour/silentfilesource.cc39
-rw-r--r--libs/ardour/sndfilesource.cc72
-rw-r--r--libs/ardour/source.cc1
-rw-r--r--libs/ardour/source_factory.cc25
-rw-r--r--libs/ardour/sse_functions_xmm.cc116
-rw-r--r--libs/ardour/tempo.cc1
-rw-r--r--libs/ardour/utils.cc1
-rw-r--r--libs/ardour/vst_plugin.cc1
-rw-r--r--libs/clearlooks/clearlooks_theme_main.c2
-rw-r--r--libs/fst/fst.h1
-rw-r--r--libs/fst/vstwin.c23
-rwxr-xr-xlibs/glibmm2/autogen.sh22
-rw-r--r--libs/gtkmm2ext/SConscript1
-rw-r--r--libs/gtkmm2ext/barcontroller.cc8
-rw-r--r--libs/gtkmm2ext/bindable_button.cc13
-rw-r--r--libs/gtkmm2ext/fastmeter.cc59
-rw-r--r--libs/gtkmm2ext/grouped_buttons.cc96
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/auto_spin.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/barcontroller.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/bindable_button.h38
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/click_box.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/doi.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/fastmeter.h5
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h48
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/gtk_ui.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/gtkutils.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/hexentry.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pixfader.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/popup.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/prompter.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/selector.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/slider_controller.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/stateful_button.h59
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/tearoff.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/textviewer.h1
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/utils.h1
-rw-r--r--libs/gtkmm2ext/stateful_button.cc101
-rw-r--r--libs/midi++2/macosx/English.lproj/InfoPlist.stringsbin0 -> 142 bytes
-rw-r--r--libs/midi++2/macosx/Info.plist26
-rw-r--r--libs/midi++2/macosx/midi++.xcodeproj/project.pbxproj498
-rw-r--r--libs/midi++2/macosx/midi++_Prefix.pch3
-rw-r--r--libs/midi++2/macosx/version.cc3
-rw-r--r--libs/midi++2/macosx/version.h7
-rw-r--r--libs/midi++2/midi++/alsa_rawmidi.h1
-rw-r--r--libs/midi++2/midi++/alsa_sequencer.h1
-rw-r--r--libs/midi++2/midi++/channel.h1
-rw-r--r--libs/midi++2/midi++/factory.h1
-rw-r--r--libs/midi++2/midi++/fd_midiport.h1
-rw-r--r--libs/midi++2/midi++/fifomidi.h1
-rw-r--r--libs/midi++2/midi++/manager.h1
-rw-r--r--libs/midi++2/midi++/mmc.h3
-rw-r--r--libs/midi++2/midi++/nullmidi.h1
-rw-r--r--libs/midi++2/midi++/parser.h5
-rw-r--r--libs/midi++2/midi++/port.h1
-rw-r--r--libs/midi++2/midi++/port_request.h1
-rw-r--r--libs/midi++2/midiparser.cc6
-rw-r--r--libs/midi++2/mmc.cc4
-rw-r--r--libs/midi++2/mtc.cc7
-rw-r--r--libs/pbd/SConscript1
-rw-r--r--libs/pbd/controllable.cc55
-rw-r--r--libs/pbd/macosx/English.lproj/InfoPlist.stringsbin0 -> 136 bytes
-rw-r--r--libs/pbd/macosx/Info.plist26
-rw-r--r--libs/pbd/macosx/pbd.xcodeproj/project.pbxproj634
-rw-r--r--libs/pbd/macosx/pbd_Prefix.pch4
-rw-r--r--libs/pbd/macosx/version.cc3
-rw-r--r--libs/pbd/macosx/version.h7
-rw-r--r--libs/pbd/pbd/abstract_ui.cc12
-rw-r--r--libs/pbd/pbd/abstract_ui.h1
-rw-r--r--libs/pbd/pbd/command.h1
-rw-r--r--libs/pbd/pbd/controllable.h11
-rw-r--r--libs/pbd/pbd/error.h1
-rw-r--r--libs/pbd/pbd/mathfix.h1
-rw-r--r--libs/pbd/pbd/memento_command.h1
-rw-r--r--libs/pbd/pbd/mountpoint.h1
-rw-r--r--libs/pbd/pbd/pool.h1
-rw-r--r--libs/pbd/pbd/rcu.h19
-rw-r--r--libs/pbd/pbd/receiver.h1
-rw-r--r--libs/pbd/pbd/replace_all.h8
-rw-r--r--libs/pbd/pbd/ringbuffer.h146
-rw-r--r--libs/pbd/pbd/ringbufferNPT.h1
-rw-r--r--libs/pbd/pbd/selectable.h1
-rw-r--r--libs/pbd/pbd/stateful.h1
-rw-r--r--libs/pbd/pbd/stl_delete.h1
-rw-r--r--libs/pbd/pbd/stl_functors.h1
-rw-r--r--libs/pbd/pbd/strsplit.h2
-rw-r--r--libs/pbd/pbd/textreceiver.h1
-rw-r--r--libs/pbd/pbd/thrown_error.h1
-rw-r--r--libs/pbd/pbd/touchable.h1
-rw-r--r--libs/pbd/pbd/transmitter.h1
-rw-r--r--libs/pbd/pbd/undo.h1
-rw-r--r--libs/pbd/stacktrace.cc8
-rw-r--r--libs/pbd/strreplace.cc19
-rw-r--r--libs/pbd/strsplit.cc39
-rwxr-xr-xlibs/sigc++2/autogen.sh21
-rw-r--r--libs/soundtouch/RateTransposer.cpp2
-rw-r--r--libs/soundtouch/RateTransposer.h2
-rw-r--r--libs/soundtouch/TDStretch.cpp7
-rw-r--r--libs/soundtouch/cpu_detect_x86_gcc.cpp2
-rw-r--r--libs/surfaces/control_protocol/basic_ui.cc1
-rw-r--r--libs/surfaces/control_protocol/control_protocol.cc1
-rw-r--r--libs/surfaces/control_protocol/control_protocol/basic_ui.h1
-rw-r--r--libs/surfaces/control_protocol/control_protocol/control_protocol.h1
-rw-r--r--libs/surfaces/frontier/kernel_drivers/BUILD10
-rw-r--r--libs/surfaces/frontier/kernel_drivers/Makefile35
-rw-r--r--libs/surfaces/frontier/kernel_drivers/README16
-rw-r--r--libs/surfaces/frontier/kernel_drivers/doc/keycodes.html35
-rw-r--r--libs/surfaces/frontier/kernel_drivers/tests/Makefile23
-rw-r--r--libs/surfaces/frontier/kernel_drivers/tests/README104
-rw-r--r--libs/surfaces/frontier/kernel_drivers/tests/tranzport.c375
-rw-r--r--libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c361
-rwxr-xr-xlibs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh27
-rw-r--r--libs/surfaces/frontier/kernel_drivers/tranzport.c1065
-rw-r--r--libs/surfaces/frontier/tests/Makefile17
-rw-r--r--libs/surfaces/frontier/tests/README104
-rw-r--r--libs/surfaces/frontier/tests/tranzport.c347
-rw-r--r--libs/surfaces/frontier/tests/tranzport_lights.c361
-rw-r--r--libs/surfaces/frontier/tranzport/SConscript56
-rw-r--r--libs/surfaces/frontier/tranzport/interface.cc51
-rw-r--r--libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc (renamed from libs/surfaces/tranzport/tranzport_control_protocol.cc)3
-rw-r--r--libs/surfaces/frontier/tranzport/tranzport_control_protocol.h320
-rw-r--r--libs/surfaces/generic_midi/SConscript4
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc34
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc5
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h1
-rw-r--r--libs/surfaces/mackie/SConscript74
-rw-r--r--libs/surfaces/mackie/TODO45
-rw-r--r--libs/surfaces/mackie/bcf_surface.cc1473
-rw-r--r--libs/surfaces/mackie/bcf_surface.h27
-rw-r--r--libs/surfaces/mackie/controls.cc109
-rw-r--r--libs/surfaces/mackie/controls.h301
-rw-r--r--libs/surfaces/mackie/interface.cc96
-rw-r--r--libs/surfaces/mackie/mackie_button_handler.cc691
-rw-r--r--libs/surfaces/mackie/mackie_button_handler.h227
-rw-r--r--libs/surfaces/mackie/mackie_control_exception.h47
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc1378
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h307
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol_poll.cc192
-rw-r--r--libs/surfaces/mackie/mackie_midi_builder.cc173
-rw-r--r--libs/surfaces/mackie/mackie_midi_builder.h81
-rw-r--r--libs/surfaces/mackie/mackie_port.cc399
-rw-r--r--libs/surfaces/mackie/mackie_port.h122
-rw-r--r--libs/surfaces/mackie/mackie_surface.cc1504
-rw-r--r--libs/surfaces/mackie/mackie_surface.h27
-rw-r--r--libs/surfaces/mackie/midi_byte_array.cc98
-rw-r--r--libs/surfaces/mackie/midi_byte_array.h76
-rw-r--r--libs/surfaces/mackie/route_signal.cc95
-rw-r--r--libs/surfaces/mackie/route_signal.h81
-rw-r--r--libs/surfaces/mackie/scripts/bank.rb32
-rw-r--r--libs/surfaces/mackie/scripts/bcf-controls.csv96
-rw-r--r--libs/surfaces/mackie/scripts/controls.rb208
-rwxr-xr-xlibs/surfaces/mackie/scripts/dump.rb11
-rw-r--r--libs/surfaces/mackie/scripts/generate-button-handlers-cc.erb59
-rw-r--r--libs/surfaces/mackie/scripts/generate-button-handlers-h.erb54
-rwxr-xr-xlibs/surfaces/mackie/scripts/generate-surface.rb26
-rwxr-xr-xlibs/surfaces/mackie/scripts/host.rb133
-rw-r--r--libs/surfaces/mackie/scripts/mackie-controls.csv93
-rw-r--r--libs/surfaces/mackie/scripts/mackie.rb119
-rw-r--r--libs/surfaces/mackie/scripts/parse.rb61
-rw-r--r--libs/surfaces/mackie/scripts/signals.rb137
-rw-r--r--libs/surfaces/mackie/scripts/simple_host.rb137
-rw-r--r--libs/surfaces/mackie/scripts/surface-cc-template.erb95
-rw-r--r--libs/surfaces/mackie/scripts/surface-h-template.erb27
-rwxr-xr-xlibs/surfaces/mackie/scripts/test_controls.rb9
-rw-r--r--libs/surfaces/mackie/scripts/transform.rb26
-rw-r--r--libs/surfaces/mackie/scripts/write.rb10
-rw-r--r--libs/surfaces/mackie/surface.cc142
-rw-r--r--libs/surfaces/mackie/surface.h94
-rw-r--r--libs/surfaces/mackie/surface_port.cc178
-rw-r--r--libs/surfaces/mackie/surface_port.h100
-rw-r--r--libs/surfaces/mackie/test.cc25
-rw-r--r--libs/surfaces/mackie/types.cc9
-rw-r--r--libs/surfaces/mackie/types.h93
-rw-r--r--libs/surfaces/tranzport/README90
-rw-r--r--libs/surfaces/tranzport/SConscript46
-rw-r--r--libs/surfaces/tranzport/TODO6
-rw-r--r--libs/surfaces/tranzport/bling.cc115
-rw-r--r--libs/surfaces/tranzport/button_events.cc380
-rw-r--r--libs/surfaces/tranzport/button_yn.cc21
-rw-r--r--libs/surfaces/tranzport/buttons.cc113
-rw-r--r--libs/surfaces/tranzport/general.cc333
-rw-r--r--libs/surfaces/tranzport/init.cc314
-rw-r--r--libs/surfaces/tranzport/interface.cc20
-rw-r--r--libs/surfaces/tranzport/io.cc95
-rw-r--r--libs/surfaces/tranzport/io_kernel.cc144
-rw-r--r--libs/surfaces/tranzport/io_midi.cc26
-rw-r--r--libs/surfaces/tranzport/io_usb.cc232
-rw-r--r--libs/surfaces/tranzport/lcd.cc120
-rw-r--r--libs/surfaces/tranzport/lights.cc95
-rw-r--r--libs/surfaces/tranzport/meter.cc21
-rw-r--r--libs/surfaces/tranzport/mode.cc107
-rw-r--r--libs/surfaces/tranzport/mode_loop.cc21
-rw-r--r--libs/surfaces/tranzport/mode_tuner.cc21
-rw-r--r--libs/surfaces/tranzport/panner.cc34
-rw-r--r--libs/surfaces/tranzport/screen.cc93
-rw-r--r--libs/surfaces/tranzport/show.cc400
-rw-r--r--libs/surfaces/tranzport/slider_gain.h40
-rw-r--r--libs/surfaces/tranzport/state.cc148
-rw-r--r--libs/surfaces/tranzport/tranzport_base.h78
-rw-r--r--libs/surfaces/tranzport/tranzport_common.h44
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.h130
-rw-r--r--libs/surfaces/tranzport/view_automation.cc21
-rw-r--r--libs/surfaces/tranzport/view_bigmeter.cc21
-rw-r--r--libs/surfaces/tranzport/view_bling.cc21
-rw-r--r--libs/surfaces/tranzport/view_bus.cc21
-rw-r--r--libs/surfaces/tranzport/view_config.cc21
-rw-r--r--libs/surfaces/tranzport/view_layer.cc21
-rw-r--r--libs/surfaces/tranzport/view_loop.cc21
-rw-r--r--libs/surfaces/tranzport/view_manymeter.cc21
-rw-r--r--libs/surfaces/tranzport/view_marker.cc21
-rw-r--r--libs/surfaces/tranzport/view_master.cc21
-rw-r--r--libs/surfaces/tranzport/view_plugins.cc21
-rw-r--r--libs/surfaces/tranzport/view_std.cc21
-rw-r--r--libs/surfaces/tranzport/view_tempo.cc21
-rw-r--r--libs/surfaces/tranzport/view_tuner.cc21
-rw-r--r--libs/surfaces/tranzport/wheel.cc206
-rw-r--r--libs/surfaces/tranzport/wheel_modes.cc139
352 files changed, 21852 insertions, 2269 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 878b41e82a..772f847400 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -101,6 +101,7 @@ session_state.cc
session_time.cc
session_timefx.cc
session_transport.cc
+silentfilesource.cc
sndfile_helpers.cc
sndfilesource.cc
source.cc
@@ -296,16 +297,29 @@ env['BUILDERS']['SharedAsmObject'] = Builder (action = '$CXX -c -fPIC $SOURCE -o
suffix = '$SHOBJSUFFIX',
src_suffix = '.s',
single_source = 1)
+#
+# handle objects that should always be compiled with -msse in their own
+# special environment, which is exactly like "ardour" but unconditionally
+# includes -msse
+#
+
+
+always_sse_objects = []
+sse_env = ardour.Copy()
+sse_env.Append (CXXFLAGS="-msse")
if env['FPU_OPTIMIZATION']:
if env['DIST_TARGET'] == "i386":
arch_specific_objects = env.SharedAsmObject('sse_functions.os', 'sse_functions.s')
+ always_sse_objects += [ sse_env.SharedObject (source = 'sse_functions_xmm.cc') ]
if env['DIST_TARGET'] == "i686":
arch_specific_objects = env.SharedAsmObject('sse_functions.os', 'sse_functions.s')
+ always_sse_objects += [ sse_env.SharedObject (source = 'sse_functions_xmm.cc') ]
if env['DIST_TARGET'] == "x86_64":
arch_specific_objects = env.SharedAsmObject('sse_functions_64bit.os', 'sse_functions_64bit.s')
+ always_sse_objects += [ sse_env.SharedObject (source = 'sse_functions_xmm.cc') ]
-libardour = ardour.SharedLibrary('ardour', ardour_files + extra_sources + arch_specific_objects)
+libardour = ardour.SharedLibrary('ardour', ardour_files + always_sse_objects + extra_sources + arch_specific_objects)
Default(libardour)
@@ -318,6 +332,6 @@ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ar
env.Alias('version', ardour.VersionBuild(['version.cc', 'ardour/version.h'], []))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
- [ 'SConscript', 'i18n.h', 'gettext.h', 'sse_functions.s', 'sse_functions_64bit.s' ] +
+ [ 'SConscript', 'i18n.h', 'gettext.h', 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] +
ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files +
glob.glob('po/*.po') + glob.glob('ardour/*.h')))
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index 5cc2359632..332b9af733 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_ardour_h__
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 1da8903a41..4846a20cbd 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -32,6 +32,7 @@
#include <pbd/fastlog.h>
#include <pbd/ringbufferNPT.h>
#include <pbd/stateful.h>
+#include <pbd/rcu.h>
#include <ardour/ardour.h>
#include <ardour/configuration.h>
@@ -65,24 +66,28 @@ class AudioDiskstream : public Diskstream
float capture_buffer_load() const;
string input_source (uint32_t n=0) const {
- if (n < channels.size()) {
- return channels[n].source ? channels[n].source->name() : "";
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ if (n < c->size()) {
+ return (*c)[n]->source ? (*c)[n]->source->name() : "";
} else {
return "";
}
}
Port *input_source_port (uint32_t n=0) const {
- if (n < channels.size()) return channels[n].source; return 0;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ if (n < c->size()) return (*c)[n]->source; return 0;
}
void set_record_enabled (bool yn);
int set_destructive (bool yn);
bool can_become_destructive (bool& requires_bounce) const;
- float peak_power(uint32_t n=0) {
- float x = channels[n].peak_power;
- channels[n].peak_power = 0.0f;
+ float peak_power(uint32_t n = 0) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ ChannelInfo* chaninfo = (*c)[n];
+ float x = chaninfo->peak_power;
+ chaninfo->peak_power = 0.0f;
if (x > 0.0f) {
return 20.0f * fast_log10(x);
} else {
@@ -96,27 +101,29 @@ class AudioDiskstream : public Diskstream
int use_new_playlist ();
int use_copy_playlist ();
- Sample *playback_buffer (uint32_t n=0) {
- if (n < channels.size())
- return channels[n].current_playback_buffer;
+ Sample *playback_buffer (uint32_t n = 0) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ if (n < c->size())
+ return (*c)[n]->current_playback_buffer;
return 0;
}
- Sample *capture_buffer (uint32_t n=0) {
- if (n < channels.size())
- return channels[n].current_capture_buffer;
+ Sample *capture_buffer (uint32_t n = 0) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ if (n < c->size())
+ return (*c)[n]->current_capture_buffer;
return 0;
}
boost::shared_ptr<AudioFileSource> write_source (uint32_t n=0) {
- if (n < channels.size())
- return channels[n].write_source;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ if (n < c->size())
+ return (*c)[n]->write_source;
return boost::shared_ptr<AudioFileSource>();
}
- int add_channel ();
- int remove_channel ();
-
+ int add_channel (uint32_t how_many);
+ int remove_channel (uint32_t how_many);
/* stateful */
@@ -174,12 +181,9 @@ class AudioDiskstream : public Diskstream
struct ChannelInfo {
- ChannelInfo ();
+ ChannelInfo (nframes_t buffer_size, nframes_t speed_buffer_size, nframes_t wrap_buffer_size);
~ChannelInfo ();
- void init (nframes_t buffer_size, nframes_t speed_buffer_size, nframes_t wrap_buffer_size);
- void release ();
-
Sample *playback_wrap_buffer;
Sample *capture_wrap_buffer;
Sample *speed_buffer;
@@ -208,17 +212,19 @@ class AudioDiskstream : public Diskstream
nframes_t curr_capture_cnt;
};
+ typedef std::vector<ChannelInfo*> ChannelList;
+
/* The two central butler operations */
int do_flush (Session::RunContext context, bool force = false);
int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer); }
- int do_refill_with_alloc();
+ int do_refill_with_alloc ();
int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
- nframes_t& start, nframes_t cnt,
- ChannelInfo& channel_info, int channel, bool reversed);
+ nframes_t& start, nframes_t cnt,
+ ChannelInfo* channel_info, int channel, bool reversed);
- void finish_capture (bool rec_monitors_input);
+ void finish_capture (bool rec_monitors_input, boost::shared_ptr<ChannelList>);
void transport_stopped (struct tm&, time_t, bool abort);
void init (Diskstream::Flag);
@@ -251,14 +257,17 @@ class AudioDiskstream : public Diskstream
static Sample* _mixdown_buffer;
static gain_t* _gain_buffer;
- // Uh, /really/ private? (there should probably be less friends of Diskstream)
- int _do_refill (Sample *mixdown_buffer, float *gain_buffer);
-
-
std::vector<boost::shared_ptr<AudioFileSource> > capturing_sources;
- typedef vector<ChannelInfo> ChannelList;
- ChannelList channels;
+ SerializedRCUManager<ChannelList> channels;
+
+ /* really */
+ private:
+ int _do_refill (Sample *mixdown_buffer, float *gain_buffer);
+
+ int add_channel_to (boost::shared_ptr<ChannelList>, uint32_t how_many);
+ int remove_channel_from (boost::shared_ptr<ChannelList>, uint32_t how_many);
+
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index e87434b0fb..3546545329 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_audio_track_h__
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index 3dbd30f841..48a3426d53 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_audioengine_h__
@@ -53,6 +52,8 @@ class AudioEngine : public sigc::trackable
jack_client_t* jack() const { return _jack; }
bool connected() const { return _jack != 0; }
+ bool is_realtime () const;
+
std::string client_name() const { return jack_client_name; }
int reconnect_to_jack ();
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index 0e1caf5245..913cd7d5ed 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -20,12 +20,19 @@
#ifndef __ardour_audiofilesource_h__
#define __ardour_audiofilesource_h__
+#include <exception>
+
#include <time.h>
#include <ardour/audiosource.h>
namespace ARDOUR {
+class non_existent_source : public std::exception {
+ public:
+ virtual const char *what() const throw() { return "audio file does not exist"; }
+};
+
struct SoundFileInfo {
float samplerate;
uint16_t channels;
@@ -49,17 +56,19 @@ class AudioFileSource : public AudioSource {
virtual ~AudioFileSource ();
- int set_name (string newname, bool destructive);
+ int set_name (Glib::ustring newname, bool destructive);
+
+ Glib::ustring path() const { return _path; }
+ Glib::ustring peak_path (Glib::ustring audio_path);
+ Glib::ustring old_peak_path (Glib::ustring audio_path);
- string path() const { return _path; }
- string peak_path (string audio_path);
- string old_peak_path (string audio_path);
+ uint16_t channel() const { return _channel; }
- static void set_peak_dir (string dir) { peak_dir = dir; }
+ static void set_peak_dir (Glib::ustring dir) { peak_dir = dir; }
- static bool get_soundfile_info (string path, SoundFileInfo& _info, string& error);
+ static bool get_soundfile_info (Glib::ustring path, SoundFileInfo& _info, std::string& error);
- static bool safe_file_extension (string path);
+ static bool safe_file_extension (Glib::ustring path);
void set_allow_remove_if_empty (bool yn);
void mark_for_remove();
@@ -76,19 +85,19 @@ class AudioFileSource : public AudioSource {
virtual int update_header (nframes_t when, struct tm&, time_t) = 0;
virtual int flush_header () = 0;
- int move_to_trash (const string trash_dir_name);
+ int move_to_trash (const Glib::ustring& trash_dir_name);
- static bool is_empty (Session&, string path);
+ static bool is_empty (Session&, Glib::ustring path);
void mark_streaming_write_completed ();
- void mark_take (string);
- string take_id() const { return _take_id; }
+ void mark_take (Glib::ustring);
+ Glib::ustring take_id() const { return _take_id; }
bool is_embedded() const { return _is_embedded; }
static void set_bwf_serial_number (int);
- static void set_search_path (string);
+ static void set_search_path (Glib::ustring string);
static void set_header_position_offset (nframes_t offset );
int setup_peakfile ();
@@ -100,6 +109,7 @@ class AudioFileSource : public AudioSource {
bool destructive() const { return (_flags & Destructive); }
virtual bool set_destructive (bool yn) { return false; }
+ bool can_truncate_peaks() const { return !destructive(); }
Flag flags() const { return _flags; }
@@ -116,31 +126,31 @@ class AudioFileSource : public AudioSource {
/* constructor to be called for existing external-to-session files */
- AudioFileSource (Session&, std::string path, Flag flags);
+ AudioFileSource (Session&, Glib::ustring path, Flag flags);
/* constructor to be called for new in-session files */
- AudioFileSource (Session&, std::string path, Flag flags,
+ AudioFileSource (Session&, Glib::ustring path, Flag flags,
SampleFormat samp_format, HeaderFormat hdr_format);
/* constructor to be called for existing in-session files */
- AudioFileSource (Session&, const XMLNode&);
+ AudioFileSource (Session&, const XMLNode&, bool must_exit = true);
- int init (string idstr, bool must_exist);
+ int init (Glib::ustring idstr, bool must_exist);
- string _path;
+ Glib::ustring _path;
Flag _flags;
- string _take_id;
+ Glib::ustring _take_id;
int64_t timeline_position;
bool file_is_new;
- uint16_t channel;
+ uint16_t _channel;
bool _is_embedded;
- static bool determine_embeddedness(string path);
+ static bool determine_embeddedness(Glib::ustring path);
- static string peak_dir;
- static string search_path;
+ static Glib::ustring peak_dir;
+ static Glib::ustring search_path;
static char bwf_country_code[3];
static char bwf_organization_code[4];
@@ -151,7 +161,7 @@ class AudioFileSource : public AudioSource {
virtual void set_timeline_position (int64_t pos);
virtual void set_header_timeline_position () = 0;
- bool find (std::string path, bool must_exist, bool& is_new);
+ bool find (Glib::ustring& path, bool must_exist, bool& is_new);
bool removable() const;
bool writable() const { return _flags & Writable; }
};
diff --git a/libs/ardour/ardour/audiofilter.h b/libs/ardour/ardour/audiofilter.h
index c8762dbf69..6b60544942 100644
--- a/libs/ardour/ardour/audiofilter.h
+++ b/libs/ardour/ardour/audiofilter.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_audiofilter_h__
diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h
index 36fe027a6f..39f41d5d1c 100644
--- a/libs/ardour/ardour/audioplaylist.h
+++ b/libs/ardour/ardour/audioplaylist.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_audio_playlist_h__
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index e3c5db561d..3b592a54ee 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_audio_region_h__
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 0734a66319..812c30e8c2 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: audio_source.h 486 2006-04-27 09:04:24Z pauld $
*/
#ifndef __ardour_audio_source_h__
@@ -23,7 +22,6 @@
#include <list>
#include <vector>
-#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
@@ -31,6 +29,7 @@
#include <time.h>
#include <glibmm/thread.h>
+#include <glibmm/ustring.h>
#include <sigc++/signal.h>
@@ -41,7 +40,7 @@
using std::list;
using std::vector;
-using std::string;
+using Glib::ustring;
namespace ARDOUR {
@@ -50,7 +49,7 @@ const nframes_t frames_per_peak = 256;
class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
{
public:
- AudioSource (Session&, string name);
+ AudioSource (Session&, ustring name);
AudioSource (Session&, const XMLNode&);
virtual ~AudioSource ();
@@ -64,8 +63,10 @@ const nframes_t frames_per_peak = 256;
virtual void mark_for_remove() = 0;
virtual void mark_streaming_write_completed () {}
- void set_captured_for (string str) { _captured_for = str; }
- string captured_for() const { return _captured_for; }
+ virtual bool can_truncate_peaks() const { return true; }
+
+ void set_captured_for (ustring str) { _captured_for = str; }
+ ustring captured_for() const { return _captured_for; }
uint32_t read_data_count() const { return _read_data_count; }
uint32_t write_data_count() const { return _write_data_count; }
@@ -80,10 +81,7 @@ const nframes_t frames_per_peak = 256;
XMLNode& get_state ();
int set_state (const XMLNode&);
- static int start_peak_thread ();
- static void stop_peak_thread ();
-
- int rename_peakfile (std::string newpath);
+ int rename_peakfile (ustring newpath);
void touch_peakfile ();
static void set_build_missing_peakfiles (bool yn) {
@@ -96,67 +94,41 @@ const nframes_t frames_per_peak = 256;
virtual int setup_peakfile () { return 0; }
+ int prepare_for_peakfile_writes ();
+ void done_with_peakfile_writes ();
+
protected:
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
bool _peaks_built;
mutable Glib::Mutex _lock;
- bool next_peak_clear_should_notify;
- string peakpath;
- string _captured_for;
+ ustring peakpath;
+ ustring _captured_for;
mutable uint32_t _read_data_count; // modified in read()
mutable uint32_t _write_data_count; // modified in write()
- int initialize_peakfile (bool newfile, string path);
- void build_peaks_from_scratch ();
-
- int do_build_peak (nframes_t, nframes_t);
+ int initialize_peakfile (bool newfile, ustring path);
+ int build_peaks_from_scratch ();
+ int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force);
void truncate_peakfile();
- mutable off_t _peak_byte_max; // modified in do_build_peaks()
+ mutable off_t _peak_byte_max; // modified in compute_and_write_peak()
virtual nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const = 0;
virtual nframes_t write_unlocked (Sample *dst, nframes_t cnt) = 0;
- virtual string peak_path(string audio_path) = 0;
- virtual string old_peak_path(string audio_path) = 0;
+ virtual ustring peak_path(ustring audio_path) = 0;
+ virtual ustring old_peak_path(ustring audio_path) = 0;
- static pthread_t peak_thread;
- static bool have_peak_thread;
- static void* peak_thread_work(void*);
-
- static int peak_request_pipe[2];
-
- struct PeakRequest {
- enum Type {
- Build,
- Quit
- };
- };
-
- static vector<boost::shared_ptr<AudioSource> > pending_peak_sources;
- static Glib::Mutex* pending_peak_sources_lock;
-
- static void queue_for_peaks (boost::shared_ptr<AudioSource>, bool notify=true);
- static void clear_queue_for_peaks ();
-
- struct PeakBuildRecord {
- nframes_t frame;
- nframes_t cnt;
-
- PeakBuildRecord (nframes_t f, nframes_t c)
- : frame (f), cnt (c) {}
- PeakBuildRecord (const PeakBuildRecord& other) {
- frame = other.frame;
- cnt = other.cnt;
- }
- };
-
- list<AudioSource::PeakBuildRecord *> pending_peak_builds;
-
private:
- bool file_changed (string path);
+ int peakfile;
+ nframes_t peak_leftover_cnt;
+ nframes_t peak_leftover_size;
+ Sample* peak_leftovers;
+ nframes_t peak_leftover_frame;
+
+ bool file_changed (ustring path);
};
}
diff --git a/libs/ardour/ardour/auditioner.h b/libs/ardour/ardour/auditioner.h
index e6091cfba0..06d521ea21 100644
--- a/libs/ardour/ardour/auditioner.h
+++ b/libs/ardour/ardour/auditioner.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_auditioner_h__
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index a2cfb23e61..007bad7259 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_automation_event_h__
diff --git a/libs/ardour/ardour/click.h b/libs/ardour/ardour/click.h
index 71214978a5..60499b98da 100644
--- a/libs/ardour/ardour/click.h
+++ b/libs/ardour/ardour/click.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_click_h__
diff --git a/libs/ardour/ardour/configuration.h b/libs/ardour/ardour/configuration.h
index bb49b2dce4..31cb74ab33 100644
--- a/libs/ardour/ardour/configuration.h
+++ b/libs/ardour/ardour/configuration.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_configuration_h__
diff --git a/libs/ardour/ardour/configuration_variable.h b/libs/ardour/ardour/configuration_variable.h
index 8710369a64..81e282ff64 100644
--- a/libs/ardour/ardour/configuration_variable.h
+++ b/libs/ardour/ardour/configuration_variable.h
@@ -27,10 +27,13 @@ class ConfigVariableBase {
virtual void add_to_node (XMLNode& node) = 0;
virtual bool set_from_node (const XMLNode& node, Owner owner) = 0;
+ void show_stored_value (const std::string&);
+ static void set_show_stored_values (bool yn);
protected:
std::string _name;
Owner _owner;
+ static bool show_stores;
void notify ();
void miss ();
@@ -61,7 +64,7 @@ class ConfigVariable : public ConfigVariableBase
void add_to_node (XMLNode& node) {
std::stringstream ss;
ss << value;
- cerr << "Config variable " << _name << " stored as " << ss.str() << endl;
+ show_stored_value (ss.str());
XMLNode* child = new XMLNode ("Option");
child->add_property ("name", _name);
child->add_property ("value", ss.str());
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 703352b305..674a9232b5 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -18,11 +18,14 @@ CONFIG_VARIABLE (bool, send_mmc, "send-mmc", false)
CONFIG_VARIABLE (bool, mmc_control, "mmc-control", false)
CONFIG_VARIABLE (bool, midi_feedback, "midi-feedback", false)
CONFIG_VARIABLE (bool, midi_control, "midi-control", false)
+CONFIG_VARIABLE (uint8_t, mmc_device_id, "mmc-device-id", 0)
/* control surfaces */
CONFIG_VARIABLE (uint32_t, feedback_interval_ms, "feedback-interval-ms", 100)
CONFIG_VARIABLE (bool, use_tranzport, "use-tranzport", false)
+CONFIG_VARIABLE (std::string, mackie_emulation, "mackie-emulation", "mcu")
+CONFIG_VARIABLE (RemoteModel, remote_model, "remote-model", MixerOrdered)
/* disk operations */
@@ -35,7 +38,7 @@ CONFIG_VARIABLE (HeaderFormat, native_file_header_format, "native-file-header-f
/* OSC */
CONFIG_VARIABLE (uint32_t, osc_port, "osc-port", 3819)
-CONFIG_VARIABLE (bool, use_osc, "use-osc", true)
+CONFIG_VARIABLE (bool, use_osc, "use-osc", false)
/* crossfades */
@@ -62,6 +65,7 @@ CONFIG_VARIABLE (SoloModel, solo_model, "solo-model", InverseMute)
CONFIG_VARIABLE (bool, solo_latched, "solo-latched", true)
CONFIG_VARIABLE (bool, latched_record_enable, "latched-record-enable", false)
CONFIG_VARIABLE (bool, all_safe, "all-safe", false)
+CONFIG_VARIABLE (bool, show_solo_mutes, "show-solo-mutes", false)
/* click */
diff --git a/libs/ardour/ardour/connection.h b/libs/ardour/ardour/connection.h
index da4d4e2684..d2f1cb4294 100644
--- a/libs/ardour/ardour/connection.h
+++ b/libs/ardour/ardour/connection.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_connection_h__
diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h
index 3eafed818c..7346e645fb 100644
--- a/libs/ardour/ardour/crossfade.h
+++ b/libs/ardour/ardour/crossfade.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_overlap_h__
diff --git a/libs/ardour/ardour/crossfade_compare.h b/libs/ardour/ardour/crossfade_compare.h
index 2ecf79c04c..b92806a6bb 100644
--- a/libs/ardour/ardour/crossfade_compare.h
+++ b/libs/ardour/ardour/crossfade_compare.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_crossfade_compare_h__
diff --git a/libs/ardour/ardour/curve.h b/libs/ardour/ardour/curve.h
index df984b74e0..dd63439f08 100644
--- a/libs/ardour/ardour/curve.h
+++ b/libs/ardour/ardour/curve.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_curve_h__
diff --git a/libs/ardour/ardour/cycle_timer.h b/libs/ardour/ardour/cycle_timer.h
index b9cbbbf0a8..4e1a50e602 100644
--- a/libs/ardour/ardour/cycle_timer.h
+++ b/libs/ardour/ardour/cycle_timer.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_cycle_timer_h__
diff --git a/libs/ardour/ardour/cycles.h b/libs/ardour/ardour/cycles.h
index a6f34d59be..f1422880b8 100644
--- a/libs/ardour/ardour/cycles.h
+++ b/libs/ardour/ardour/cycles.h
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_cycles_h__
diff --git a/libs/ardour/ardour/dB.h b/libs/ardour/ardour/dB.h
index 703de6fb1a..b67e581067 100644
--- a/libs/ardour/ardour/dB.h
+++ b/libs/ardour/ardour/dB.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_dB_h__
diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h
deleted file mode 100644
index 2e6f5d0e57..0000000000
--- a/libs/ardour/ardour/destructive_filesource.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- 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$
-*/
-
-#ifndef __ardour_destructive_file_source_h__
-#define __ardour_destructive_file_source_h__
-
-#include <string>
-
-#include <ardour/sndfilesource.h>
-
-struct tm;
-
-namespace ARDOUR {
-
-class DestructiveFileSource : public SndFileSource {
- public:
- DestructiveFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate,
- Flag flags = AudioFileSource::Flag (AudioFileSource::Writable));
-
- DestructiveFileSource (Session&, std::string path, Flag flags);
-
- DestructiveFileSource (Session&, const XMLNode&);
- ~DestructiveFileSource ();
-
- nframes_t last_capture_start_frame() const;
- void mark_capture_start (nframes_t);
- void mark_capture_end ();
- void clear_capture_marks();
-
- XMLNode& get_state ();
-
- static void setup_standard_crossfades (nframes_t sample_rate);
-
- int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const;
-
- protected:
- nframes_t write_unlocked (Sample *src, nframes_t cnt);
-
- virtual void handle_header_position_change ();
-
- private:
- static nframes_t xfade_frames;
- static gain_t* out_coefficient;
- static gain_t* in_coefficient;
-
- bool _capture_start;
- bool _capture_end;
- nframes_t capture_start_frame;
- nframes_t file_pos; // unit is frames
- Sample* xfade_buf;
-
- void init ();
- nframes_t crossfade (Sample* data, nframes_t cnt, int dir);
- void set_timeline_position (int64_t);
-};
-
-}
-
-#endif /* __ardour_destructive_file_source_h__ */
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index a81921b9f1..10b3bbfe92 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -15,7 +15,6 @@
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__
@@ -54,7 +53,7 @@ class Session;
class Playlist;
class IO;
- class Diskstream : public PBD::StatefulDestructible
+class Diskstream : public PBD::StatefulDestructible
{
public:
enum Flag {
@@ -199,7 +198,6 @@ class IO;
/** For non-butler contexts (allocates temporary working buffers) */
virtual int do_refill_with_alloc() = 0;
-
/* XXX fix this redundancy ... */
@@ -207,7 +205,6 @@ class IO;
virtual void playlist_modified ();
virtual void playlist_deleted (boost::weak_ptr<Playlist>);
- virtual void finish_capture (bool rec_monitors_input) = 0;
virtual void transport_stopped (struct tm&, time_t, bool abort) = 0;
struct CaptureInfo {
@@ -236,7 +233,7 @@ class IO;
virtual void use_destructive_playlist () {}
static nframes_t disk_io_chunk_frames;
- vector<CaptureInfo*> capture_info;
+ std::vector<CaptureInfo*> capture_info;
Glib::Mutex capture_info_lock;
uint32_t i_am_the_modifier;
diff --git a/libs/ardour/ardour/export.h b/libs/ardour/ardour/export.h
index f66acec893..66e5b1b7d5 100644
--- a/libs/ardour/ardour/export.h
+++ b/libs/ardour/ardour/export.h
@@ -76,9 +76,9 @@ namespace ARDOUR
/* shared between UI thread and audio thread */
- float progress; /* audio thread sets this */
- bool stop; /* UI sets this */
- bool running; /* audio thread sets to false when export is done */
+ volatile float progress; /* audio thread sets this */
+ volatile bool stop; /* UI sets this */
+ volatile bool running; /* audio thread sets to false when export is done */
int status;
diff --git a/libs/ardour/ardour/gain.h b/libs/ardour/ardour/gain.h
index 3613ea1a5a..5832f71101 100644
--- a/libs/ardour/ardour/gain.h
+++ b/libs/ardour/ardour/gain.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_gain_h__
diff --git a/libs/ardour/ardour/gdither.h b/libs/ardour/ardour/gdither.h
index 51343b13c4..67efcc3583 100644
--- a/libs/ardour/ardour/gdither.h
+++ b/libs/ardour/ardour/gdither.h
@@ -15,7 +15,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id$
*/
#ifndef GDITHER_H
diff --git a/libs/ardour/ardour/gdither_types.h b/libs/ardour/ardour/gdither_types.h
index 46feb55fbc..bcc0097d7f 100644
--- a/libs/ardour/ardour/gdither_types.h
+++ b/libs/ardour/ardour/gdither_types.h
@@ -15,7 +15,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id$
*/
#ifndef GDITHER_TYPES_H
diff --git a/libs/ardour/ardour/gdither_types_internal.h b/libs/ardour/ardour/gdither_types_internal.h
index 55d5792833..e73a256310 100644
--- a/libs/ardour/ardour/gdither_types_internal.h
+++ b/libs/ardour/ardour/gdither_types_internal.h
@@ -15,7 +15,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id$
*/
#ifndef GDITHER_TYPES_H
diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h
index 31e59e6704..e58cb71754 100644
--- a/libs/ardour/ardour/insert.h
+++ b/libs/ardour/ardour/insert.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_insert_h__
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index c4df46415b..51423e9ab2 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_io_h__
@@ -113,7 +112,8 @@ class IO : public PBD::StatefulDestructible
Panner& panner() { return *_panner; }
PeakMeter& peak_meter() { return *_meter; }
-
+ const Panner& panner() const { return *_panner; }
+
int ensure_io (ChanCount in, ChanCount out, bool clear, void *src);
int use_input_connection (Connection&, void *src);
diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h
index 27e8bc5e84..f1f1bb8811 100644
--- a/libs/ardour/ardour/ladspa_plugin.h
+++ b/libs/ardour/ardour/ladspa_plugin.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_ladspa_plugin_h__
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index 57e13de5af..6625b7dbf5 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_location_h__
@@ -159,11 +158,11 @@ class Locations : public PBD::StatefulDestructible
int set_current (Location *, bool want_lock = true);
Location *current () const { return current_location; }
- Location *first_location_before (nframes_t);
- Location *first_location_after (nframes_t);
+ Location *first_location_before (nframes_t, bool include_special_ranges = false);
+ Location *first_location_after (nframes_t, bool include_special_ranges = false);
- nframes_t first_mark_before (nframes_t);
- nframes_t first_mark_after (nframes_t);
+ nframes_t first_mark_before (nframes_t, bool include_special_ranges = false);
+ nframes_t first_mark_after (nframes_t, bool include_special_ranges = false);
sigc::signal<void,Location*> current_changed;
sigc::signal<void> changed;
diff --git a/libs/ardour/ardour/logcurve.h b/libs/ardour/ardour/logcurve.h
index ac60a10fd7..dd58263313 100644
--- a/libs/ardour/ardour/logcurve.h
+++ b/libs/ardour/ardour/logcurve.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_logcurve_h__
diff --git a/libs/ardour/ardour/mix.h b/libs/ardour/ardour/mix.h
index 653b61cb95..5555f5437e 100644
--- a/libs/ardour/ardour/mix.h
+++ b/libs/ardour/ardour/mix.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_mix_h__
#define __ardour_mix_h__
@@ -28,7 +27,7 @@
extern "C" {
/* SSE functions */
- float x86_sse_compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
+ float x86_sse_compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
void x86_sse_apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain);
@@ -37,9 +36,11 @@ extern "C" {
void x86_sse_mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes);
}
+void x86_sse_find_peaks (ARDOUR::Sample *buf, nframes_t nsamples, float *min, float *max);
+
/* debug wrappers for SSE functions */
-float debug_compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
+float debug_compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
void debug_apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain);
@@ -53,6 +54,8 @@ void debug_mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nfra
float veclib_compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
+void veclib_find_peaks (ARDOUR::Sample *buf, nframes_t nsamples, float *min, float *max);
+
void veclib_apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain);
void veclib_mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes, float gain);
@@ -63,12 +66,14 @@ void veclib_mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src
/* non-optimized functions */
-float compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
+float compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current);
+
+void find_peaks (ARDOUR::Sample *buf, nframes_t nsamples, float *min, float *max);
-void apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain);
+void apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain);
-void mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes, float gain);
+void mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes, float gain);
-void mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes);
+void mix_buffers_no_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes);
#endif /* __ardour_mix_h__ */
diff --git a/libs/ardour/ardour/named_selection.h b/libs/ardour/ardour/named_selection.h
index fd5777ccf6..7636099e1f 100644
--- a/libs/ardour/ardour/named_selection.h
+++ b/libs/ardour/ardour/named_selection.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_named_selection_h__
diff --git a/libs/ardour/ardour/osc.h b/libs/ardour/ardour/osc.h
index 0a34f44a41..ca2f4488dd 100644
--- a/libs/ardour/ardour/osc.h
+++ b/libs/ardour/ardour/osc.h
@@ -15,7 +15,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * $Id$
*/
#ifndef ardour_osc_h
diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h
index 79bff7d2a5..9d6a7e7fb6 100644
--- a/libs/ardour/ardour/panner.h
+++ b/libs/ardour/ardour/panner.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_panner_h__
diff --git a/libs/ardour/ardour/pcm_utils.h b/libs/ardour/ardour/pcm_utils.h
index 6866e53251..5e6436cc94 100644
--- a/libs/ardour/ardour/pcm_utils.h
+++ b/libs/ardour/ardour/pcm_utils.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_pcm_utils_h__
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index 9893f7391a..54863b6fb0 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_playlist_h__
diff --git a/libs/ardour/ardour/playlist_templates.h b/libs/ardour/ardour/playlist_templates.h
index 603e0bef37..bf072a71c1 100644
--- a/libs/ardour/ardour/playlist_templates.h
+++ b/libs/ardour/ardour/playlist_templates.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_playlist_templates_h__
diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h
index 431b55db8b..feb86f1b7b 100644
--- a/libs/ardour/ardour/plugin.h
+++ b/libs/ardour/ardour/plugin.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_plugin_h__
diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h
index 8e6c0bd1c7..b4d2e5e99d 100644
--- a/libs/ardour/ardour/plugin_manager.h
+++ b/libs/ardour/ardour/plugin_manager.h
@@ -7,7 +7,6 @@
#include <ardour/types.h>
#include <ardour/plugin.h>
-#include <ardour/audio_unit.h>
namespace ARDOUR {
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index 4e4ad0fec6..7891a0e6f2 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_port_h__
diff --git a/libs/ardour/ardour/redirect.h b/libs/ardour/ardour/redirect.h
index 8c3de09c10..fac2241f14 100644
--- a/libs/ardour/ardour/redirect.h
+++ b/libs/ardour/ardour/redirect.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_redirect_h__
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 46865d8357..716c7dec20 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_region_h__
diff --git a/libs/ardour/ardour/reverse.h b/libs/ardour/ardour/reverse.h
index c60df990f2..3296c77c62 100644
--- a/libs/ardour/ardour/reverse.h
+++ b/libs/ardour/ardour/reverse.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_reverse_h__
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 2f94e0c80a..70091ef85d 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_route_h__
@@ -78,8 +77,8 @@ class Route : public IO
std::string comment() { return _comment; }
void set_comment (std::string str, void *src);
- long order_key(std::string name) const;
- void set_order_key (std::string name, long n);
+ long order_key (const char* name) const;
+ void set_order_key (const char* name, long n);
bool hidden() const { return _flags & Hidden; }
bool master() const { return _flags & MasterOut; }
@@ -121,6 +120,7 @@ class Route : public IO
void set_mute (bool yn, void *src);
bool muted() const { return _muted; }
+ bool solo_muted() const { return desired_solo_gain == 0.0; }
void set_mute_config (mute_type, bool, void *src);
bool get_mute_config (mute_type);
@@ -256,7 +256,6 @@ class Route : public IO
bool _muted : 1;
bool _soloed : 1;
- bool _solo_muted : 1;
bool _solo_safe : 1;
bool _recordable : 1;
bool _active : 1;
@@ -324,7 +323,16 @@ class Route : public IO
void init ();
static uint32_t order_key_cnt;
- typedef std::map<std::string,long> OrderKeys;
+
+ struct ltstr
+ {
+ bool operator()(const char* s1, const char* s2) const
+ {
+ return strcmp(s1, s2) < 0;
+ }
+ };
+
+ typedef std::map<const char*,long,ltstr> OrderKeys;
OrderKeys order_keys;
void input_change_handler (IOChange, void *src);
diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h
index d87d3fa3a4..55448df45b 100644
--- a/libs/ardour/ardour/route_group.h
+++ b/libs/ardour/ardour/route_group.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_route_group_h__
diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h
index eceb301bf8..d4c0572811 100644
--- a/libs/ardour/ardour/send.h
+++ b/libs/ardour/ardour/send.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_send_h__
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 63fa608499..2022b21a05 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -1,22 +1,21 @@
- /*
- Copyright (C) 2000 Paul Davis
+/*
+ Copyright (C) 2000 Paul Davis
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ This program is 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.
+ 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.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
- */
+*/
#ifndef __ardour_session_h__
#define __ardour_session_h__
@@ -176,7 +175,7 @@ class Session : public PBD::StatefulDestructible
Route* route;
};
- boost::shared_ptr<Region> region;
+ boost::shared_ptr<Region> region;
list<AudioRange> audio_range;
list<MusicRange> music_range;
@@ -248,6 +247,7 @@ class Session : public PBD::StatefulDestructible
string name() const { return _name; }
string snap_name() const { return _current_snapshot_name; }
string raid_path () const;
+ string export_dir () const;
void set_snap_name ();
@@ -491,6 +491,8 @@ class Session : public PBD::StatefulDestructible
void resort_routes ();
void resort_routes_using (boost::shared_ptr<RouteList>);
+ void set_remote_control_ids();
+
AudioEngine &engine() { return _engine; };
int32_t max_level;
@@ -591,13 +593,14 @@ class Session : public PBD::StatefulDestructible
int start_audio_export (ARDOUR::AudioExportSpecification&);
int stop_audio_export (ARDOUR::AudioExportSpecification&);
-
+ void finalize_audio_export ();
+
void add_source (boost::shared_ptr<Source>);
void remove_source (boost::weak_ptr<Source>);
struct cleanup_report {
vector<string> paths;
- int32_t space;
+ int64_t space;
};
int cleanup_sources (cleanup_report&);
@@ -626,6 +629,7 @@ class Session : public PBD::StatefulDestructible
boost::shared_ptr<MidiSource> create_midi_source_for_session (ARDOUR::MidiDiskstream&);
boost::shared_ptr<Source> source_by_id (const PBD::ID&);
+ boost::shared_ptr<Source> source_by_path_and_channel (const Glib::ustring&, uint16_t);
/* playlist management */
@@ -683,6 +687,7 @@ class Session : public PBD::StatefulDestructible
void set_all_mute (bool);
sigc::signal<void,bool> SoloActive;
+ sigc::signal<void> SoloChanged;
void record_disenable_all ();
void record_enable_all ();
@@ -740,6 +745,8 @@ class Session : public PBD::StatefulDestructible
void deliver_midi (MIDI::Port*, MIDI::byte*, int32_t size);
+ void set_mmc_device_id (uint32_t id);
+
/* Scrubbing */
void start_scrub (nframes_t where);
@@ -920,12 +927,14 @@ class Session : public PBD::StatefulDestructible
void* ptr,
float opt);
- typedef float (*compute_peak_t) (Sample *, nframes_t, float);
+ typedef float (*compute_peak_t) (Sample *, nframes_t, float);
+ typedef void (*find_peaks_t) (Sample *, nframes_t, float *, float*);
typedef void (*apply_gain_to_buffer_t) (Sample *, nframes_t, float);
typedef void (*mix_buffers_with_gain_t) (Sample *, Sample *, nframes_t, float);
typedef void (*mix_buffers_no_gain_t) (Sample *, Sample *, nframes_t);
- static compute_peak_t compute_peak;
+ static compute_peak_t compute_peak;
+ static find_peaks_t find_peaks;
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;
@@ -1283,8 +1292,7 @@ class Session : public PBD::StatefulDestructible
void mmc_record_pause (MIDI::MachineControl &);
void mmc_record_strobe (MIDI::MachineControl &);
void mmc_record_exit (MIDI::MachineControl &);
- void mmc_track_record_status (MIDI::MachineControl &,
- uint32_t track, bool enabled);
+ void mmc_track_record_status (MIDI::MachineControl &, uint32_t track, bool enabled);
void mmc_fast_forward (MIDI::MachineControl &);
void mmc_rewind (MIDI::MachineControl &);
void mmc_locate (MIDI::MachineControl &, const MIDI::byte *);
@@ -1566,7 +1574,9 @@ class Session : public PBD::StatefulDestructible
static const char* dead_sound_dir_name;
static const char* interchange_dir_name;
static const char* peak_dir_name;
-
+ static const char* export_dir_name;
+
+ string old_sound_dir (bool with_path = true) const;
string discover_best_sound_dir (bool destructive = false);
int ensure_sound_dir (string, string&);
void refresh_disk_space ();
diff --git a/libs/ardour/ardour/session_connection.h b/libs/ardour/ardour/session_connection.h
index addc896b0b..d5e32c7904 100644
--- a/libs/ardour/ardour/session_connection.h
+++ b/libs/ardour/ardour/session_connection.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_session_connection_h__
diff --git a/libs/ardour/ardour/session_playlist.h b/libs/ardour/ardour/session_playlist.h
index 20cf4d8f2e..baeb74916d 100644
--- a/libs/ardour/ardour/session_playlist.h
+++ b/libs/ardour/ardour/session_playlist.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_session_playlist_h__
diff --git a/libs/ardour/ardour/session_route.h b/libs/ardour/ardour/session_route.h
index feacc14775..0c70bf407d 100644
--- a/libs/ardour/ardour/session_route.h
+++ b/libs/ardour/ardour/session_route.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_session_route_h__
diff --git a/libs/ardour/ardour/session_selection.h b/libs/ardour/ardour/session_selection.h
index a110c2c3da..4169a3a511 100644
--- a/libs/ardour/ardour/session_selection.h
+++ b/libs/ardour/ardour/session_selection.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_session_named_selection_h__
diff --git a/libs/ardour/ardour/silentfilesource.h b/libs/ardour/ardour/silentfilesource.h
new file mode 100644
index 0000000000..92ef076a9b
--- /dev/null
+++ b/libs/ardour/ardour/silentfilesource.h
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2007 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_silentfilesource_h__
+#define __ardour_silentfilesource_h__
+
+#include <ardour/audiofilesource.h>
+
+namespace ARDOUR {
+
+class SilentFileSource : public AudioFileSource {
+ public:
+ virtual ~SilentFileSource ();
+
+ int update_header (nframes_t when, struct tm&, time_t) { return 0; }
+ int flush_header () { return 0; }
+ float sample_rate () const { return _sample_rate; }
+
+ void set_length (nframes_t len);
+
+ int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const {
+ memset (peaks, 0, sizeof (PeakData) * npeaks);
+ return 0;
+ }
+
+ bool destructive() const { return false; }
+
+ protected:
+
+ float _sample_rate;
+
+ SilentFileSource (Session&, const XMLNode&, nframes_t nframes, float sample_rate);
+
+ friend class SourceFactory;
+
+ nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const {
+ memset (dst, 0, sizeof (Sample) * cnt);
+ return cnt;
+ }
+
+ nframes_t write_unlocked (Sample *dst, nframes_t cnt) { return 0; }
+
+ void set_header_timeline_position () {}
+
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_audiofilesource_h__ */
+
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
index d4a7e2f22a..170facb1de 100644
--- a/libs/ardour/ardour/slave.h
+++ b/libs/ardour/ardour/slave.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_slave_h__
@@ -70,6 +69,7 @@ class MTC_Slave : public Slave, public sigc::trackable {
Session& session;
MIDI::Port* port;
std::vector<sigc::connection> connections;
+ bool can_notify_on_unknown_rate;
struct SafeTime {
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index a5000a4b63..2fc3872887 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __sndfile_source_h__
@@ -31,11 +30,11 @@ class SndFileSource : public AudioFileSource {
public:
/* constructor to be called for existing external-to-session files */
- SndFileSource (Session&, std::string path, int chn, Flag flags);
+ SndFileSource (Session&, Glib::ustring path, int chn, Flag flags);
/* constructor to be called for new in-session files */
- SndFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate,
+ SndFileSource (Session&, Glib::ustring path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate,
Flag flags = SndFileSource::default_writable_flags);
/* constructor to be called for existing in-session files */
@@ -60,7 +59,7 @@ class SndFileSource : public AudioFileSource {
static void setup_standard_crossfades (nframes_t sample_rate);
static const AudioFileSource::Flag default_writable_flags;
- static int get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg);
+ static int get_soundfile_info (const Glib::ustring& path, SoundFileInfo& _info, string& error_msg);
protected:
void set_header_timeline_position ();
diff --git a/libs/ardour/ardour/soundseq.h b/libs/ardour/ardour/soundseq.h
index 4a318e9750..c7157428ee 100644
--- a/libs/ardour/ardour/soundseq.h
+++ b/libs/ardour/ardour/soundseq.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __soundseq_h__
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index 8eaab14ec5..45c91950fc 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_source_h__
diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h
index b69645b031..a8b0ae54a3 100644
--- a/libs/ardour/ardour/source_factory.h
+++ b/libs/ardour/ardour/source_factory.h
@@ -20,8 +20,8 @@ class SourceFactory {
static sigc::signal<void,boost::shared_ptr<Source> > SourceCreated;
static boost::shared_ptr<Source> create (Session&, const XMLNode& node);
+ static boost::shared_ptr<Source> createSilent (Session&, const XMLNode& node, nframes_t nframes, float sample_rate);
- // MIDI sources will have to be hacked in here somehow
static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path, int chn, AudioFileSource::Flag flags, bool announce = true);
static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate, bool announce = true);
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index f8751b5d2b..5e3e93e48b 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_tempo_h__
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 30cdcd8232..b155965cab 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_types_h__
@@ -265,6 +264,12 @@ namespace ARDOUR {
ExternalMonitoring,
};
+ enum RemoteModel {
+ UserOrdered,
+ MixerOrdered,
+ EditorOrdered,
+ };
+
enum CrossfadeModel {
FullCrossfade,
ShortCrossfade
@@ -346,6 +351,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::HeaderFormat& sf);
std::istream& operator>>(std::istream& o, ARDOUR::AutoConnectOption& sf);
std::istream& operator>>(std::istream& o, ARDOUR::EditMode& sf);
std::istream& operator>>(std::istream& o, ARDOUR::MonitorModel& sf);
+std::istream& operator>>(std::istream& o, ARDOUR::RemoteModel& sf);
std::istream& operator>>(std::istream& o, ARDOUR::SoloModel& sf);
std::istream& operator>>(std::istream& o, ARDOUR::LayerModel& sf);
std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeModel& sf);
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index de97a5c150..20badf5ea1 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_utils_h__
diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h
index 8034341bcc..f7ec486d36 100644
--- a/libs/ardour/ardour/vst_plugin.h
+++ b/libs/ardour/ardour/vst_plugin.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_vst_plugin_h__
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 7165a58b27..eeaa095fbd 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -36,6 +36,7 @@
#include <pbd/xml++.h>
#include <pbd/memento_command.h>
#include <pbd/enumwriter.h>
+#include <pbd/stacktrace.h>
#include <ardour/ardour.h>
#include <ardour/audioengine.h>
@@ -43,7 +44,6 @@
#include <ardour/utils.h>
#include <ardour/configuration.h>
#include <ardour/audiofilesource.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/send.h>
#include <ardour/region_factory.h>
#include <ardour/audioplaylist.h>
@@ -67,6 +67,7 @@ gain_t* AudioDiskstream::_gain_buffer = 0;
AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
: Diskstream(sess, name, flag)
, deprecated_io_node(NULL)
+ , channels (new ChannelList)
{
/* prevent any write sources from being created */
@@ -81,6 +82,7 @@ AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream:
AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node)
: Diskstream(sess, node)
, deprecated_io_node(NULL)
+ , channels (new ChannelList)
{
in_set_state = true;
init (Recordable);
@@ -110,7 +112,7 @@ AudioDiskstream::init (Diskstream::Flag f)
set_block_size (_session.get_block_size());
allocate_temporary_buffers ();
- add_channel ();
+ add_channel (1);
assert(_n_channels == ChanCount(DataType::AUDIO, 1));
}
@@ -119,16 +121,17 @@ AudioDiskstream::~AudioDiskstream ()
notify_callbacks ();
{
- /* don't be holding this lock as we exit the destructor, glib will wince
- visibly since the mutex gets destroyed before we release it.
- */
-
- Glib::Mutex::Lock lm (state_lock);
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- (*chan).release ();
+ RCUWriter<ChannelList> writer (channels);
+ boost::shared_ptr<ChannelList> c = writer.get_copy();
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ delete *chan;
}
- channels.clear();
+
+ c->clear();
}
+
+ channels.flush ();
}
void
@@ -154,37 +157,26 @@ AudioDiskstream::free_working_buffers()
void
AudioDiskstream::non_realtime_input_change ()
{
- {
+ {
Glib::Mutex::Lock lm (state_lock);
if (input_change_pending == NoChange) {
return;
}
- if (input_change_pending & ConfigurationChanged) {
-
+ {
+ RCUWriter<ChannelList> writer (channels);
+ boost::shared_ptr<ChannelList> c = writer.get_copy();
+
+ _n_channels.set(DataType::AUDIO, c->size());
+
if (_io->n_inputs().get(DataType::AUDIO) > _n_channels.get(DataType::AUDIO)) {
-
- // we need to add new channel infos
-
- int diff = _io->n_inputs().get(DataType::AUDIO) - channels.size();
-
- for (int i = 0; i < diff; ++i) {
- add_channel ();
- }
-
- } else if (_io->n_inputs().get(DataType::AUDIO) < _n_channels.get(DataType::AUDIO)) {
-
- // we need to get rid of channels
-
- int diff = channels.size() - _io->n_inputs().get(DataType::AUDIO);
-
- for (int i = 0; i < diff; ++i) {
- remove_channel ();
- }
+ add_channel_to (c, _io->n_inputs().get(DataType::AUDIO) - _n_channels.get(DataType::AUDIO));
+ } else if (_io->n_inputs().get(DataType::AUDIO) < _n_channels.get(DataType::AUDIO)) {
+ remove_channel_from (c, _n_channels.get(DataType::AUDIO) - _io->n_inputs().get(DataType::AUDIO));
}
- }
-
+ }
+
get_input_sources ();
set_capture_offset ();
@@ -194,10 +186,12 @@ AudioDiskstream::non_realtime_input_change ()
} else {
set_align_style_from_io ();
}
-
+
input_change_pending = NoChange;
- }
+ /* implicit unlock */
+ }
+
/* reset capture files */
reset_write_sources (false);
@@ -214,23 +208,26 @@ AudioDiskstream::non_realtime_input_change ()
void
AudioDiskstream::get_input_sources ()
{
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ uint32_t n;
+ ChannelList::iterator chan;
uint32_t ni = _io->n_inputs().get(DataType::AUDIO);
-
- for (uint32_t n = 0; n < ni; ++n) {
+
+ for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) {
const char **connections = _io->input(n)->get_connections ();
- ChannelInfo& chan = channels[n];
if (connections == 0 || connections[0] == 0) {
- if (chan.source) {
+ if ((*chan)->source) {
// _source->disable_metering ();
}
- chan.source = 0;
+ (*chan)->source = 0;
} else {
- chan.source = dynamic_cast<AudioPort*>(
+ (*chan)->source = dynamic_cast<AudioPort*>(
_session.engine().get_port_by_name (connections[0]) );
}
@@ -324,9 +321,10 @@ void
AudioDiskstream::setup_destructive_playlist ()
{
SourceList srcs;
-
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- srcs.push_back ((*chan).write_source);
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ srcs.push_back ((*chan)->write_source);
}
/* a single full-sized region */
@@ -363,15 +361,16 @@ AudioDiskstream::use_destructive_playlist ()
uint32_t n;
ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
- for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
- (*chan).write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n));
- assert((*chan).write_source);
- (*chan).write_source->set_allow_remove_if_empty (false);
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+ (*chan)->write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n));
+ assert((*chan)->write_source);
+ (*chan)->write_source->set_allow_remove_if_empty (false);
/* this might be false if we switched modes, so force it */
- (*chan).write_source->set_destructive (true);
+ (*chan)->write_source->set_destructive (true);
}
/* the source list will never be reset for a destructive track */
@@ -467,15 +466,16 @@ AudioDiskstream::check_record_status (nframes_t transport_frame, nframes_t nfram
}
if (_flags & Recordable) {
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
RingBufferNPT<CaptureTransition>::rw_vector transvec;
- (*chan).capture_transition_buf->get_write_vector(&transvec);
+ (*chan)->capture_transition_buf->get_write_vector(&transvec);
if (transvec.len[0] > 0) {
transvec.buf[0]->type = CaptureStart;
transvec.buf[0]->capture_val = capture_start_frame;
- (*chan).capture_transition_buf->increment_write_ptr(1);
+ (*chan)->capture_transition_buf->increment_write_ptr(1);
}
else {
// bad!
@@ -505,7 +505,8 @@ int
AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t offset, bool can_record, bool rec_monitors_input)
{
uint32_t n;
- ChannelList::iterator c;
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ ChannelList::iterator chan;
int ret = -1;
nframes_t rec_offset = 0;
nframes_t rec_nframes = 0;
@@ -542,13 +543,13 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
// If we can't take the state lock return.
if (!state_lock.trylock()) {
return 1;
- }
+ }
adjust_capture_position = 0;
- for (c = channels.begin(); c != channels.end(); ++c) {
- (*c).current_capture_buffer = 0;
- (*c).current_playback_buffer = 0;
+ for (chan = c->begin(); chan != c->end(); ++chan) {
+ (*chan)->current_capture_buffer = 0;
+ (*chan)->current_playback_buffer = 0;
}
if (nominally_recording || (_session.get_record_enabled() && Config->get_punch_in())) {
@@ -609,15 +610,15 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
if (nominally_recording || rec_nframes) {
- for (n = 0, c = channels.begin(); c != channels.end(); ++c, ++n) {
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
- ChannelInfo& chan (*c);
-
- chan.capture_buf->get_write_vector (&chan.capture_vector);
+ ChannelInfo* chaninfo (*chan);
- if (rec_nframes <= chan.capture_vector.len[0]) {
+ chaninfo->capture_buf->get_write_vector (&chaninfo->capture_vector);
+
+ if (rec_nframes <= chaninfo->capture_vector.len[0]) {
- chan.current_capture_buffer = chan.capture_vector.buf[0];
+ chaninfo->current_capture_buffer = chaninfo->capture_vector.buf[0];
/* note: grab the entire port buffer, but only copy what we were supposed to for recording, and use
rec_offset
@@ -626,12 +627,11 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
AudioPort* const ap = _io->audio_input(n);
assert(ap);
assert(rec_nframes <= ap->get_audio_buffer().capacity());
-
- memcpy (chan.current_capture_buffer, ap->get_audio_buffer().data(rec_nframes, offset + rec_offset), sizeof (Sample) * rec_nframes);
+ memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer().data(rec_nframes, offset + rec_offset), sizeof (Sample) * rec_nframes);
} else {
- nframes_t total = chan.capture_vector.len[0] + chan.capture_vector.len[1];
+ nframes_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
if (rec_nframes > total) {
DiskOverrun ();
@@ -642,21 +642,21 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
assert(ap);
Sample* buf = ap->get_audio_buffer().data(nframes, offset);
- nframes_t first = chan.capture_vector.len[0];
+ nframes_t first = chaninfo->capture_vector.len[0];
- memcpy (chan.capture_wrap_buffer, buf, sizeof (Sample) * first);
- memcpy (chan.capture_vector.buf[0], buf, sizeof (Sample) * first);
- memcpy (chan.capture_wrap_buffer+first, buf + first, sizeof (Sample) * (rec_nframes - first));
- memcpy (chan.capture_vector.buf[1], buf + first, sizeof (Sample) * (rec_nframes - first));
+ memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
+ memcpy (chaninfo->capture_vector.buf[0], buf, sizeof (Sample) * first);
+ memcpy (chaninfo->capture_wrap_buffer+first, buf + first, sizeof (Sample) * (rec_nframes - first));
+ memcpy (chaninfo->capture_vector.buf[1], buf + first, sizeof (Sample) * (rec_nframes - first));
- chan.current_capture_buffer = chan.capture_wrap_buffer;
+ chaninfo->current_capture_buffer = chaninfo->capture_wrap_buffer;
}
}
} else {
if (was_recording) {
- finish_capture (rec_monitors_input);
+ finish_capture (rec_monitors_input, c);
}
}
@@ -667,8 +667,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
if (rec_nframes == nframes && rec_offset == 0) {
- for (c = channels.begin(); c != channels.end(); ++c) {
- (*c).current_playback_buffer = (*c).current_capture_buffer;
+ for (chan = c->begin(); chan != c->end(); ++chan) {
+ (*chan)->current_playback_buffer = (*chan)->current_capture_buffer;
}
playback_distance = nframes;
@@ -690,8 +690,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
/* can't do actual capture yet - waiting for latency effects to finish before we start*/
- for (c = channels.begin(); c != channels.end(); ++c) {
- (*c).current_playback_buffer = (*c).current_capture_buffer;
+ for (chan = c->begin(); chan != c->end(); ++chan) {
+ (*chan)->current_playback_buffer = (*chan)->current_capture_buffer;
}
playback_distance = nframes;
@@ -715,22 +715,22 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
necessary_samples = nframes;
}
- for (c = channels.begin(); c != channels.end(); ++c) {
- (*c).playback_buf->get_read_vector (&(*c).playback_vector);
+ for (chan = c->begin(); chan != c->end(); ++chan) {
+ (*chan)->playback_buf->get_read_vector (&(*chan)->playback_vector);
}
n = 0;
- for (c = channels.begin(); c != channels.end(); ++c, ++n) {
-
- ChannelInfo& chan (*c);
+ for (chan = c->begin(); chan != c->end(); ++chan, ++n) {
+
+ ChannelInfo* chaninfo (*chan);
- if (necessary_samples <= chan.playback_vector.len[0]) {
+ if (necessary_samples <= chaninfo->playback_vector.len[0]) {
- chan.current_playback_buffer = chan.playback_vector.buf[0];
+ chaninfo->current_playback_buffer = chaninfo->playback_vector.buf[0];
} else {
- nframes_t total = chan.playback_vector.len[0] + chan.playback_vector.len[1];
+ nframes_t total = chaninfo->playback_vector.len[0] + chaninfo->playback_vector.len[1];
if (necessary_samples > total) {
DiskUnderrun ();
@@ -738,12 +738,12 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
} else {
- memcpy ((char *) chan.playback_wrap_buffer, chan.playback_vector.buf[0],
- chan.playback_vector.len[0] * sizeof (Sample));
- memcpy (chan.playback_wrap_buffer + chan.playback_vector.len[0], chan.playback_vector.buf[1],
- (necessary_samples - chan.playback_vector.len[0]) * sizeof (Sample));
+ memcpy ((char *) chaninfo->playback_wrap_buffer, chaninfo->playback_vector.buf[0],
+ chaninfo->playback_vector.len[0] * sizeof (Sample));
+ memcpy (chaninfo->playback_wrap_buffer + chaninfo->playback_vector.len[0], chaninfo->playback_vector.buf[1],
+ (necessary_samples - chaninfo->playback_vector.len[0]) * sizeof (Sample));
- chan.current_playback_buffer = chan.playback_wrap_buffer;
+ chaninfo->current_playback_buffer = chaninfo->playback_wrap_buffer;
}
}
}
@@ -756,10 +756,10 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
// Linearly interpolate into the alt buffer
// using 40.24 fixp maths (swh)
- for (c = channels.begin(); c != channels.end(); ++c) {
+ for (chan = c->begin(); chan != c->end(); ++chan) {
float fr;
- ChannelInfo& chan (*c);
+ ChannelInfo* chaninfo (*chan);
i = 0;
phase = last_phase;
@@ -767,13 +767,13 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_
for (nframes_t outsample = 0; outsample < nframes; ++outsample) {
i = phase >> 24;
fr = (phase & 0xFFFFFF) / 16777216.0f;
- chan.speed_buffer[outsample] =
- chan.current_playback_buffer[i] * (1.0f - fr) +
- chan.current_playback_buffer[i+1] * fr;
+ chaninfo->speed_buffer[outsample] =
+ chaninfo->current_playback_buffer[i] * (1.0f - fr) +
+ chaninfo->current_playback_buffer[i+1] * fr;
phase += phi;
}
- chan.current_playback_buffer = chan.speed_buffer;
+ chaninfo->current_playback_buffer = chaninfo->speed_buffer;
}
playback_distance = i + 1;
@@ -813,12 +813,13 @@ AudioDiskstream::commit (nframes_t nframes)
playback_sample += playback_distance;
}
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
- (*chan).playback_buf->increment_read_ptr (playback_distance);
+ (*chan)->playback_buf->increment_read_ptr (playback_distance);
if (adjust_capture_position) {
- (*chan).capture_buf->increment_write_ptr (adjust_capture_position);
+ (*chan)->capture_buf->increment_write_ptr (adjust_capture_position);
}
}
@@ -828,14 +829,13 @@ AudioDiskstream::commit (nframes_t nframes)
}
if (_slaved) {
- need_butler = channels[0].playback_buf->write_space() >= channels[0].playback_buf->bufsize() / 2;
+ need_butler = c->front()->playback_buf->write_space() >= c->front()->playback_buf->bufsize() / 2;
} else {
- need_butler = channels[0].playback_buf->write_space() >= disk_io_chunk_frames
- || channels[0].capture_buf->read_space() >= disk_io_chunk_frames;
+ need_butler = c->front()->playback_buf->write_space() >= disk_io_chunk_frames
+ || c->front()->capture_buf->read_space() >= disk_io_chunk_frames;
}
state_lock.unlock();
-
_processed = false;
return need_butler;
@@ -849,12 +849,13 @@ AudioDiskstream::set_pending_overwrite (bool yn)
pending_overwrite = yn;
overwrite_frame = playback_sample;
- overwrite_offset = channels.front().playback_buf->get_read_ptr();
+ overwrite_offset = channels.reader()->front()->playback_buf->get_read_ptr();
}
int
AudioDiskstream::overwrite_existing_buffers ()
{
+ boost::shared_ptr<ChannelList> c = channels.reader();
Sample* mixdown_buffer;
float* gain_buffer;
int ret = -1;
@@ -863,7 +864,7 @@ AudioDiskstream::overwrite_existing_buffers ()
overwrite_queued = false;
/* assume all are the same size */
- nframes_t size = channels[0].playback_buf->bufsize();
+ nframes_t size = c->front()->playback_buf->bufsize();
mixdown_buffer = new Sample[size];
gain_buffer = new float[size];
@@ -874,7 +875,7 @@ AudioDiskstream::overwrite_existing_buffers ()
uint32_t n=0;
nframes_t start;
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++n) {
start = overwrite_frame;
nframes_t cnt = size;
@@ -892,7 +893,7 @@ AudioDiskstream::overwrite_existing_buffers ()
nframes_t to_read = size - overwrite_offset;
- if (read ((*chan).playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, *chan, n, reversed)) {
+ if (read ((*chan)->playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, *chan, n, reversed)) {
error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"),
_id, size, playback_sample) << endmsg;
goto out;
@@ -902,7 +903,7 @@ AudioDiskstream::overwrite_existing_buffers ()
cnt -= to_read;
- if (read ((*chan).playback_buf->buffer(), mixdown_buffer, gain_buffer,
+ if (read ((*chan)->playback_buf->buffer(), mixdown_buffer, gain_buffer,
start, cnt, *chan, n, reversed)) {
error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"),
_id, size, playback_sample) << endmsg;
@@ -923,25 +924,27 @@ AudioDiskstream::overwrite_existing_buffers ()
int
AudioDiskstream::seek (nframes_t frame, bool complete_refill)
{
- Glib::Mutex::Lock lm (state_lock);
uint32_t n;
int ret = -1;
ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
- for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
- (*chan).playback_buf->reset ();
- (*chan).capture_buf->reset ();
+ Glib::Mutex::Lock lm (state_lock);
+
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+ (*chan)->playback_buf->reset ();
+ (*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_with_alloc ()) > 0) ;
} else {
@@ -955,9 +958,10 @@ int
AudioDiskstream::can_internal_playback_seek (nframes_t distance)
{
ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
- for (chan = channels.begin(); chan != channels.end(); ++chan) {
- if ((*chan).playback_buf->read_space() < distance) {
+ for (chan = c->begin(); chan != c->end(); ++chan) {
+ if ((*chan)->playback_buf->read_space() < distance) {
return false;
}
}
@@ -968,9 +972,10 @@ int
AudioDiskstream::internal_playback_seek (nframes_t distance)
{
ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
- for (chan = channels.begin(); chan != channels.end(); ++chan) {
- (*chan).playback_buf->increment_read_ptr (distance);
+ for (chan = c->begin(); chan != c->end(); ++chan) {
+ (*chan)->playback_buf->increment_read_ptr (distance);
}
first_recordable_frame += distance;
@@ -981,7 +986,7 @@ AudioDiskstream::internal_playback_seek (nframes_t distance)
int
AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, nframes_t& start, nframes_t cnt,
- ChannelInfo& channel_info, int channel, bool reversed)
+ ChannelInfo* channel_info, int channel, bool reversed)
{
nframes_t this_read = 0;
bool reloop = false;
@@ -991,7 +996,10 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
nframes_t offset = 0;
Location *loc = 0;
+ /* XXX we don't currently play loops in reverse. not sure why */
+
if (!reversed) {
+
/* Make the use of a Location atomic for this read operation.
Note: Locations don't get deleted, so all we care about
@@ -1015,11 +1023,16 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
start = loop_start + ((start - loop_start) % loop_length);
//cerr << "to " << start << endl;
}
+
//cerr << "start is " << start << " loopstart: " << loop_start << " loopend: " << loop_end << endl;
}
while (cnt) {
+ if (reversed) {
+ start -= cnt;
+ }
+
/* take any loop into account. we can't read past the end of the loop. */
if (loc && (loop_end - start < cnt)) {
@@ -1047,9 +1060,6 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
if (reversed) {
- /* don't adjust start, since caller has already done that
- */
-
swap_by_ptr (buf, buf + this_read - 1);
} else {
@@ -1071,7 +1081,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
}
int
-AudioDiskstream::do_refill_with_alloc()
+AudioDiskstream::do_refill_with_alloc ()
{
Sample* mix_buf = new Sample[disk_io_chunk_frames];
float* gain_buf = new float[disk_io_chunk_frames];
@@ -1095,17 +1105,27 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
nframes_t zero_fill;
uint32_t chan_n;
ChannelList::iterator i;
+ boost::shared_ptr<ChannelList> c = channels.reader();
nframes_t ts;
+ if (c->empty()) {
+ return 0;
+ }
+
assert(mixdown_buffer);
assert(gain_buffer);
- channels.front().playback_buf->get_write_vector (&vector);
+ vector.buf[0] = 0;
+ vector.len[0] = 0;
+ vector.buf[1] = 0;
+ vector.len[1] = 0;
+
+ c->front()->playback_buf->get_write_vector (&vector);
if ((total_space = vector.len[0] + vector.len[1]) == 0) {
return 0;
}
-
+
/* 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.
@@ -1131,10 +1151,12 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
work with.
*/
- if (_slaved && total_space < (channels.front().playback_buf->bufsize() / 2)) {
+ if (_slaved && total_space < (c->front()->playback_buf->bufsize() / 2)) {
return 0;
}
+ /* never do more than disk_io_chunk_frames worth of disk input per call (limit doesn't apply for memset) */
+
total_space = min (disk_io_chunk_frames, total_space);
if (reversed) {
@@ -1143,15 +1165,15 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
/* at start: nothing to do but fill with silence */
- for (chan_n = 0, i = channels.begin(); i != channels.end(); ++i, ++chan_n) {
+ for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
- ChannelInfo& chan (*i);
- chan.playback_buf->get_write_vector (&vector);
+ ChannelInfo* chan (*i);
+ chan->playback_buf->get_write_vector (&vector);
memset (vector.buf[0], 0, sizeof(Sample) * vector.len[0]);
if (vector.len[1]) {
memset (vector.buf[1], 0, sizeof(Sample) * vector.len[1]);
}
- chan.playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]);
+ chan->playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]);
}
return 0;
}
@@ -1168,11 +1190,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
} else {
- /* move read position backwards because we are going
- to reverse the data.
- */
-
- file_frame -= total_space;
zero_fill = 0;
}
@@ -1182,15 +1199,15 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
/* at end: nothing to do but fill with silence */
- for (chan_n = 0, i = channels.begin(); i != channels.end(); ++i, ++chan_n) {
+ for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
- ChannelInfo& chan (*i);
- chan.playback_buf->get_write_vector (&vector);
+ ChannelInfo* chan (*i);
+ chan->playback_buf->get_write_vector (&vector);
memset (vector.buf[0], 0, sizeof(Sample) * vector.len[0]);
if (vector.len[1]) {
memset (vector.buf[1], 0, sizeof(Sample) * vector.len[1]);
}
- chan.playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]);
+ chan->playback_buf->increment_write_ptr (vector.len[0] + vector.len[1]);
}
return 0;
}
@@ -1209,30 +1226,45 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
nframes_t file_frame_tmp = 0;
- for (chan_n = 0, i = channels.begin(); i != channels.end(); ++i, ++chan_n) {
+ for (chan_n = 0, i = c->begin(); i != c->end(); ++i, ++chan_n) {
- ChannelInfo& chan (*i);
+ ChannelInfo* chan (*i);
Sample* buf1;
Sample* buf2;
nframes_t len1, len2;
- chan.playback_buf->get_write_vector (&vector);
+ chan->playback_buf->get_write_vector (&vector);
+
+ if (vector.len[0] > disk_io_chunk_frames) {
+
+ /* we're not going to fill the first chunk, so certainly do not bother with the
+ other part. it won't be connected with the part we do fill, as in:
+
+ .... => writable space
+ ++++ => readable space
+ ^^^^ => 1 x disk_io_chunk_frames that would be filled
+
+ |......|+++++++++++++|...............................|
+ buf1 buf0
+ ^^^^^^^^^^^^^^^
+
+
+ So, just pretend that the buf1 part isn't there.
+
+ */
+
+ vector.buf[1] = 0;
+ vector.len[1] = 0;
+
+ }
ts = total_space;
file_frame_tmp = file_frame;
- if (reversed) {
- buf1 = vector.buf[1];
- len1 = vector.len[1];
- buf2 = vector.buf[0];
- len2 = vector.len[0];
- } else {
- buf1 = vector.buf[0];
- len1 = vector.len[0];
- buf2 = vector.buf[1];
- len2 = vector.len[1];
- }
-
+ buf1 = vector.buf[0];
+ len1 = vector.len[0];
+ buf2 = vector.buf[1];
+ len2 = vector.len[1];
to_read = min (ts, len1);
to_read = min (to_read, disk_io_chunk_frames);
@@ -1243,8 +1275,8 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
ret = -1;
goto out;
}
-
- chan.playback_buf->increment_write_ptr (to_read);
+
+ chan->playback_buf->increment_write_ptr (to_read);
ts -= to_read;
}
@@ -1252,7 +1284,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
if (to_read) {
-
/* we read all of vector.len[0], but it wasn't an entire disk_io_chunk_frames of data,
so read some or all of vector.len[1] as well.
*/
@@ -1262,7 +1293,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
goto out;
}
- chan.playback_buf->increment_write_ptr (to_read);
+ chan->playback_buf->increment_write_ptr (to_read);
}
if (zero_fill) {
@@ -1299,13 +1330,18 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
_write_data_count = 0;
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ transvec.buf[0] = 0;
+ transvec.buf[1] = 0;
+ vector.buf[0] = 0;
+ vector.buf[1] = 0;
+
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
- (*chan).capture_buf->get_read_vector (&vector);
+ (*chan)->capture_buf->get_read_vector (&vector);
total = vector.len[0] + vector.len[1];
-
if (total == 0 || (total < disk_io_chunk_frames && !force_flush && was_recording)) {
goto out;
}
@@ -1331,7 +1367,7 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
// important that we get this after the capture buf
if (destructive()) {
- (*chan).capture_transition_buf->get_read_vector(&transvec);
+ (*chan)->capture_transition_buf->get_read_vector(&transvec);
size_t transcount = transvec.len[0] + transvec.len[1];
bool have_start = false;
size_t ti;
@@ -1342,8 +1378,8 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
if (captrans.type == CaptureStart) {
// by definition, the first data we got above represents the given capture pos
- (*chan).write_source->mark_capture_start (captrans.capture_val);
- (*chan).curr_capture_cnt = 0;
+ (*chan)->write_source->mark_capture_start (captrans.capture_val);
+ (*chan)->curr_capture_cnt = 0;
have_start = true;
}
@@ -1351,17 +1387,17 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
// capture end, the capture_val represents total frames in capture
- if (captrans.capture_val <= (*chan).curr_capture_cnt + to_write) {
+ if (captrans.capture_val <= (*chan)->curr_capture_cnt + to_write) {
// shorten to make the write a perfect fit
- uint32_t nto_write = (captrans.capture_val - (*chan).curr_capture_cnt);
+ uint32_t nto_write = (captrans.capture_val - (*chan)->curr_capture_cnt);
if (nto_write < to_write) {
ret = 1; // should we?
}
to_write = nto_write;
- (*chan).write_source->mark_capture_end ();
+ (*chan)->write_source->mark_capture_end ();
// increment past this transition, but go no further
++ti;
@@ -1376,17 +1412,17 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
}
if (ti > 0) {
- (*chan).capture_transition_buf->increment_read_ptr(ti);
+ (*chan)->capture_transition_buf->increment_read_ptr(ti);
}
}
- if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write) != to_write) {
+ if ((!(*chan)->write_source) || (*chan)->write_source->write (vector.buf[0], to_write) != to_write) {
error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
return -1;
}
- (*chan).capture_buf->increment_read_ptr (to_write);
- (*chan).curr_capture_cnt += to_write;
+ (*chan)->capture_buf->increment_read_ptr (to_write);
+ (*chan)->curr_capture_cnt += to_write;
if ((to_write == vector.len[0]) && (total > to_write) && (to_write < disk_io_chunk_frames) && !destructive()) {
@@ -1394,18 +1430,18 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
disk_io_chunk_frames of data, so arrange for some part
of vector.len[1] to be flushed to disk as well.
*/
-
+
to_write = min ((nframes_t)(disk_io_chunk_frames - to_write), (nframes_t) vector.len[1]);
-
- if ((*chan).write_source->write (vector.buf[1], to_write) != to_write) {
+
+ if ((*chan)->write_source->write (vector.buf[1], to_write) != to_write) {
error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
return -1;
}
- _write_data_count += (*chan).write_source->write_data_count();
+ _write_data_count += (*chan)->write_source->write_data_count();
- (*chan).capture_buf->increment_read_ptr (to_write);
- (*chan).curr_capture_cnt += to_write;
+ (*chan)->capture_buf->increment_read_ptr (to_write);
+ (*chan)->curr_capture_cnt += to_write;
}
}
@@ -1425,10 +1461,11 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
SourceList::iterator src;
ChannelList::iterator chan;
vector<CaptureInfo*>::iterator ci;
+ boost::shared_ptr<ChannelList> c = channels.reader();
uint32_t n = 0;
bool mark_write_completed = false;
- finish_capture (true);
+ finish_capture (true, c);
/* butler is already stopped, but there may be work to do
to flush remaining data to disk.
@@ -1460,13 +1497,13 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
goto outout;
}
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
- if ((*chan).write_source) {
+ if ((*chan)->write_source) {
- (*chan).write_source->mark_for_remove ();
- (*chan).write_source->drop_references ();
- (*chan).write_source.reset ();
+ (*chan)->write_source->mark_for_remove ();
+ (*chan)->write_source->drop_references ();
+ (*chan)->write_source.reset ();
}
/* new source set up in "out" below */
@@ -1481,15 +1518,15 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
/* figure out the name for this take */
- for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
- boost::shared_ptr<AudioFileSource> s = (*chan).write_source;
+ boost::shared_ptr<AudioFileSource> s = (*chan)->write_source;
if (s) {
srcs.push_back (s);
s->update_header (capture_info.front()->start, when, twhen);
s->set_captured_for (_name);
-
+ s->mark_immutable ();
}
}
@@ -1508,7 +1545,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
} else {
string whole_file_region_name;
- whole_file_region_name = region_name_from_path (channels[0].write_source->name(), true);
+ whole_file_region_name = region_name_from_path (c->front()->write_source->name(), true);
/* Register a new region with the Session that
describes the entire source. Do this first
@@ -1517,7 +1554,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
*/
try {
- boost::shared_ptr<Region> rx (RegionFactory::create (srcs, channels[0].write_source->last_capture_start_frame(), total_capture,
+ boost::shared_ptr<Region> rx (RegionFactory::create (srcs, c->front()->write_source->last_capture_start_frame(), total_capture,
whole_file_region_name,
0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile)));
@@ -1538,7 +1575,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
XMLNode &before = _playlist->get_state();
_playlist->freeze ();
- for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+ for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
string region_name;
@@ -1588,7 +1625,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
}
void
-AudioDiskstream::finish_capture (bool rec_monitors_input)
+AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<ChannelList> c)
{
was_recording = false;
@@ -1597,16 +1634,16 @@ AudioDiskstream::finish_capture (bool rec_monitors_input)
}
if (recordable() && destructive()) {
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
RingBufferNPT<CaptureTransition>::rw_vector transvec;
- (*chan).capture_transition_buf->get_write_vector(&transvec);
+ (*chan)->capture_transition_buf->get_write_vector(&transvec);
if (transvec.len[0] > 0) {
transvec.buf[0]->type = CaptureEnd;
transvec.buf[0]->capture_val = capture_captured;
- (*chan).capture_transition_buf->increment_write_ptr(1);
+ (*chan)->capture_transition_buf->increment_write_ptr(1);
}
else {
// bad!
@@ -1649,7 +1686,7 @@ AudioDiskstream::set_record_enabled (bool yn)
return;
}
- if (yn && channels[0].source == 0) {
+ if (yn && channels.reader()->front()->source == 0) {
/* pick up connections not initiated *from* the IO object
we're associated with.
@@ -1674,20 +1711,24 @@ AudioDiskstream::set_record_enabled (bool yn)
void
AudioDiskstream::engage_record_enable ()
{
- bool rolling = _session.transport_speed() != 0.0f;
+ bool rolling = _session.transport_speed() != 0.0f;
+ boost::shared_ptr<ChannelList> c = channels.reader();
g_atomic_int_set (&_record_enabled, 1);
capturing_sources.clear ();
+
if (Config->get_monitoring_model() == HardwareMonitoring) {
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- if ((*chan).source) {
- (*chan).source->ensure_monitor_input (!(Config->get_auto_input() && rolling));
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ if ((*chan)->source) {
+ (*chan)->source->ensure_monitor_input (!(Config->get_auto_input() && rolling));
}
- capturing_sources.push_back ((*chan).write_source);
+ 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);
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ capturing_sources.push_back ((*chan)->write_source);
}
}
@@ -1698,17 +1739,17 @@ void
AudioDiskstream::disengage_record_enable ()
{
g_atomic_int_set (&_record_enabled, 0);
- if (Config->get_monitoring_model() == HardwareMonitoring) {
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- if ((*chan).source) {
- (*chan).source->ensure_monitor_input (false);
+ boost::shared_ptr<ChannelList> c = channels.reader();
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ if (Config->get_monitoring_model() == HardwareMonitoring) {
+ if ((*chan)->source) {
+ (*chan)->source->ensure_monitor_input (false);
}
}
}
capturing_sources.clear ();
RecordEnableChanged (); /* EMIT SIGNAL */
}
-
XMLNode&
AudioDiskstream::get_state ()
@@ -1716,10 +1757,11 @@ AudioDiskstream::get_state ()
XMLNode* node = new XMLNode ("AudioDiskstream");
char buf[64] = "";
LocaleGuard lg (X_("POSIX"));
+ boost::shared_ptr<ChannelList> c = channels.reader();
node->add_property ("flags", enum_2_string (_flags));
- snprintf (buf, sizeof(buf), "%zd", channels.size());
+ snprintf (buf, sizeof(buf), "%zd", c->size());
node->add_property ("channels", buf);
node->add_property ("playlist", _playlist->name());
@@ -1814,27 +1856,15 @@ AudioDiskstream::set_state (const XMLNode& node)
// create necessary extra channels
// we are always constructed with one and we always need one
+ _n_channels.set(DataType::AUDIO, channels.reader()->size());
+
if (nchans > _n_channels.get(DataType::AUDIO)) {
- // we need to add new channel infos
- //LockMonitor lm (state_lock, __LINE__, __FILE__);
-
- int diff = nchans - channels.size();
-
- for (int i=0; i < diff; ++i) {
- add_channel ();
- }
+ add_channel (nchans - _n_channels.get(DataType::AUDIO));
} else if (nchans < _n_channels.get(DataType::AUDIO)) {
- // we need to get rid of channels
- //LockMonitor lm (state_lock, __LINE__, __FILE__);
-
- int diff = channels.size() - nchans;
-
- for (int i = 0; i < diff; ++i) {
- remove_channel ();
- }
+ remove_channel (_n_channels.get(DataType::AUDIO) - nchans);
}
if ((prop = node.property ("playlist")) == 0) {
@@ -1870,8 +1900,6 @@ AudioDiskstream::set_state (const XMLNode& node)
}
}
- _n_channels.set(DataType::AUDIO, channels.size());
-
in_set_state = false;
/* make sure this is clear before we do anything else */
@@ -1890,37 +1918,40 @@ AudioDiskstream::set_state (const XMLNode& node)
int
AudioDiskstream::use_new_write_source (uint32_t n)
{
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
if (!recordable()) {
return 1;
}
- if (n >= channels.size()) {
+ if (n >= c->size()) {
error << string_compose (_("AudioDiskstream: channel %1 out of range"), n) << endmsg;
return -1;
}
- ChannelInfo &chan = channels[n];
+ ChannelInfo* chan = (*c)[n];
- if (chan.write_source) {
- chan.write_source->set_allow_remove_if_empty (true);
- chan.write_source.reset ();
+ if (chan->write_source) {
+ chan->write_source->done_with_peakfile_writes ();
+ chan->write_source->set_allow_remove_if_empty (true);
+ chan->write_source.reset ();
}
try {
- if ((chan.write_source = _session.create_audio_source_for_session (*this, n, destructive())) == 0) {
+ if ((chan->write_source = _session.create_audio_source_for_session (*this, n, destructive())) == 0) {
throw failed_constructor();
}
}
catch (failed_constructor &err) {
error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
- chan.write_source.reset ();
+ chan->write_source.reset ();
return -1;
}
/* do not remove destructive files even if they are empty */
- chan.write_source->set_allow_remove_if_empty (!destructive());
+ chan->write_source->set_allow_remove_if_empty (!destructive());
return 0;
}
@@ -1929,6 +1960,7 @@ void
AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force)
{
ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
uint32_t n;
if (!recordable()) {
@@ -1937,20 +1969,20 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force)
capturing_sources.clear ();
- for (chan = channels.begin(), n = 0; chan != channels.end(); ++chan, ++n) {
+ for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
if (!destructive()) {
- if ((*chan).write_source && mark_write_complete) {
- (*chan).write_source->mark_streaming_write_completed ();
+ if ((*chan)->write_source && mark_write_complete) {
+ (*chan)->write_source->mark_streaming_write_completed ();
}
use_new_write_source (n);
if (record_enabled()) {
- capturing_sources.push_back ((*chan).write_source);
+ capturing_sources.push_back ((*chan)->write_source);
}
} else {
- if ((*chan).write_source == 0) {
+ if ((*chan)->write_source == 0) {
use_new_write_source (n);
}
}
@@ -1972,11 +2004,12 @@ int
AudioDiskstream::rename_write_sources ()
{
ChannelList::iterator chan;
+ boost::shared_ptr<ChannelList> c = channels.reader();
uint32_t n;
- for (chan = channels.begin(), n = 0; chan != channels.end(); ++chan, ++n) {
- if ((*chan).write_source != 0) {
- (*chan).write_source->set_name (_name, destructive());
+ for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
+ if ((*chan)->write_source != 0) {
+ (*chan)->write_source->set_name (_name, destructive());
/* XXX what to do if one of them fails ? */
}
}
@@ -1989,10 +2022,11 @@ AudioDiskstream::set_block_size (nframes_t nframes)
{
if (_session.get_block_size() > speed_buffer_size) {
speed_buffer_size = _session.get_block_size();
+ boost::shared_ptr<ChannelList> c = channels.reader();
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- if ((*chan).speed_buffer) delete [] (*chan).speed_buffer;
- (*chan).speed_buffer = new Sample[speed_buffer_size];
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ if ((*chan)->speed_buffer) delete [] (*chan)->speed_buffer;
+ (*chan)->speed_buffer = new Sample[speed_buffer_size];
}
}
allocate_temporary_buffers ();
@@ -2011,11 +2045,13 @@ AudioDiskstream::allocate_temporary_buffers ()
if (required_wrap_size > wrap_buffer_size) {
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- if ((*chan).playback_wrap_buffer) delete [] (*chan).playback_wrap_buffer;
- (*chan).playback_wrap_buffer = new Sample[required_wrap_size];
- if ((*chan).capture_wrap_buffer) delete [] (*chan).capture_wrap_buffer;
- (*chan).capture_wrap_buffer = new Sample[required_wrap_size];
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ if ((*chan)->playback_wrap_buffer) delete [] (*chan)->playback_wrap_buffer;
+ (*chan)->playback_wrap_buffer = new Sample[required_wrap_size];
+ if ((*chan)->capture_wrap_buffer) delete [] (*chan)->capture_wrap_buffer;
+ (*chan)->capture_wrap_buffer = new Sample[required_wrap_size];
}
wrap_buffer_size = required_wrap_size;
@@ -2025,10 +2061,12 @@ AudioDiskstream::allocate_temporary_buffers ()
void
AudioDiskstream::monitor_input (bool yn)
{
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
- if ((*chan).source) {
- (*chan).source->ensure_monitor_input (yn);
+ if ((*chan)->source) {
+ (*chan)->source->ensure_monitor_input (yn);
}
}
}
@@ -2044,8 +2082,10 @@ AudioDiskstream::set_align_style_from_io ()
get_input_sources ();
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- if ((*chan).source && (*chan).source->flags() & JackPortIsPhysical) {
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+ if ((*chan)->source && (*chan)->source->flags() & JackPortIsPhysical) {
have_physical = true;
break;
}
@@ -2059,55 +2099,64 @@ AudioDiskstream::set_align_style_from_io ()
}
int
-AudioDiskstream::add_channel ()
+AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
{
- /* XXX need to take lock??? */
+ while (how_many--) {
+ c->push_back (new ChannelInfo(_session.diskstream_buffer_size(), speed_buffer_size, wrap_buffer_size));
+ }
- /* this copies the ChannelInfo, which currently has no buffers. kind
- of pointless really, but we want the channels list to contain
- actual objects, not pointers to objects. mostly for convenience,
- which isn't much in evidence.
- */
+ _n_channels.set(DataType::AUDIO, c->size());
+
+ return 0;
+}
- channels.push_back (ChannelInfo());
+int
+AudioDiskstream::add_channel (uint32_t how_many)
+{
+ RCUWriter<ChannelList> writer (channels);
+ boost::shared_ptr<ChannelList> c = writer.get_copy();
- /* now allocate the buffers */
+ return add_channel_to (c, how_many);
+}
- channels.back().init (_session.diskstream_buffer_size(),
- speed_buffer_size,
- wrap_buffer_size);
+int
+AudioDiskstream::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
+{
+ while (--how_many && !c->empty()) {
+ delete c->back();
+ c->pop_back();
+ }
- _n_channels.set(DataType::AUDIO, channels.size());
+ _n_channels.set(DataType::AUDIO, c->size());
return 0;
}
int
-AudioDiskstream::remove_channel ()
+AudioDiskstream::remove_channel (uint32_t how_many)
{
- if (channels.size() > 1) {
- /* XXX need to take lock??? */
- channels.back().release ();
- channels.pop_back();
- _n_channels.set(DataType::AUDIO, channels.size());
- return 0;
- }
-
- return -1;
+ RCUWriter<ChannelList> writer (channels);
+ boost::shared_ptr<ChannelList> c = writer.get_copy();
+
+ return remove_channel_from (c, how_many);
}
float
AudioDiskstream::playback_buffer_load () const
{
- return (float) ((double) channels.front().playback_buf->read_space()/
- (double) channels.front().playback_buf->bufsize());
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ return (float) ((double) c->front()->playback_buf->read_space()/
+ (double) c->front()->playback_buf->bufsize());
}
float
AudioDiskstream::capture_buffer_load () const
{
- return (float) ((double) channels.front().capture_buf->write_space()/
- (double) channels.front().capture_buf->bufsize());
+ boost::shared_ptr<ChannelList> c = channels.reader();
+
+ return (float) ((double) c->front()->capture_buf->write_space()/
+ (double) c->front()->capture_buf->bufsize());
}
int
@@ -2270,24 +2319,14 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
return true;
}
-AudioDiskstream::ChannelInfo::ChannelInfo ()
+AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_size, nframes_t wrap_size)
{
- playback_wrap_buffer = 0;
- capture_wrap_buffer = 0;
- speed_buffer = 0;
peak_power = 0.0f;
source = 0;
current_capture_buffer = 0;
current_playback_buffer = 0;
curr_capture_cnt = 0;
- playback_buf = 0;
- capture_buf = 0;
- capture_transition_buf = 0;
-}
-void
-AudioDiskstream::ChannelInfo::init (nframes_t bufsize, nframes_t speed_size, nframes_t wrap_size)
-{
speed_buffer = new Sample[speed_size];
playback_wrap_buffer = new Sample[wrap_size];
capture_wrap_buffer = new Sample[wrap_size];
@@ -2309,11 +2348,6 @@ AudioDiskstream::ChannelInfo::init (nframes_t bufsize, nframes_t speed_size, nfr
AudioDiskstream::ChannelInfo::~ChannelInfo ()
{
-}
-
-void
-AudioDiskstream::ChannelInfo::release ()
-{
if (write_source) {
write_source.reset ();
}
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index a6d73e8544..9dd7064f69 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
@@ -388,7 +387,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
-
+
try {
switch (c) {
case OverlapNone:
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index b0ac7a4bd7..111bd9f4a9 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <sigc++/retype.h>
@@ -61,6 +60,7 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
}
boost::shared_ptr<AudioDiskstream> ds (new AudioDiskstream (_session, name, dflags));
+
_session.add_diskstream (ds);
set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (ds), this);
@@ -276,14 +276,7 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base)
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
- if (child->name() == X_("remote_control")) {
- if ((prop = child->property (X_("id"))) != 0) {
- int32_t x;
- sscanf (prop->value().c_str(), "%d", &x);
- set_remote_control_id (x);
- }
-
- } else if (child->name() == X_("recenable")) {
+ if (child->name() == X_("recenable")) {
_rec_enable_control.set_state (*child);
_session.add_controllable (&_rec_enable_control);
}
@@ -329,11 +322,6 @@ AudioTrack::state(bool full_state)
align_node->add_property (X_("style"), enum_2_string (as));
root.add_child_nocopy (*align_node);
- 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);
- root.add_child_nocopy (*remote_control_node);
-
root.add_property (X_("mode"), enum_2_string (_mode));
/* we don't return diskstream state because we don't
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 816e3bbf0c..6fc97703d6 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -15,16 +15,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <unistd.h>
#include <cerrno>
#include <vector>
#include <exception>
+#include <stdexcept>
#include <glibmm/timer.h>
#include <pbd/pthread_utils.h>
+#include <pbd/stacktrace.h>
#include <pbd/unknown_type.h>
#include <ardour/audioengine.h>
@@ -229,9 +230,9 @@ AudioEngine::jack_sync_callback (jack_transport_state_t state, jack_position_t*
{
if (_jack && session) {
return session->jack_sync_callback (state, pos);
- } else {
- return true;
}
+
+ return true;
}
int
@@ -296,6 +297,7 @@ AudioEngine::process_callback (nframes_t nframes)
if (_freewheeling) {
if (Freewheel (nframes)) {
+ cerr << "Freewheeling returned non-zero!\n";
_freewheeling = false;
jack_set_freewheel (_jack, false);
}
@@ -1187,8 +1189,13 @@ int
AudioEngine::request_buffer_size (nframes_t nframes)
{
if (_jack) {
- int ret = jack_set_buffer_size (_jack, nframes);
- return ret;
+
+ if (nframes == jack_get_buffer_size (_jack)) {
+ return 0;
+ }
+
+ return jack_set_buffer_size (_jack, nframes);
+
} else {
return -1;
}
@@ -1239,3 +1246,12 @@ AudioEngine::make_port_name_non_relative (string portname)
return str;
}
+bool
+AudioEngine::is_realtime () const
+{
+ if (_jack) {
+ return jack_is_realtime (_jack);
+ } else {
+ return false;
+ }
+}
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index fa38cca0a0..1d10109aa1 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -53,9 +53,10 @@
using namespace ARDOUR;
using namespace PBD;
+using namespace Glib;
-string AudioFileSource::peak_dir = "";
-string AudioFileSource::search_path;
+ustring AudioFileSource::peak_dir = "";
+ustring AudioFileSource::search_path;
sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged;
uint64_t AudioFileSource::header_position_offset = 0;
@@ -63,9 +64,9 @@ uint64_t AudioFileSource::header_position_offset = 0;
/* XXX maybe this too */
char AudioFileSource::bwf_serial_number[13] = "000000000000";
-AudioFileSource::AudioFileSource (Session& s, string path, Flag flags)
+AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags)
: AudioSource (s, path), _flags (flags),
- channel (0)
+ _channel (0)
{
/* constructor used for existing external to session files. file must exist already */
_is_embedded = AudioFileSource::determine_embeddedness (path);
@@ -76,9 +77,9 @@ AudioFileSource::AudioFileSource (Session& s, string path, Flag flags)
}
-AudioFileSource::AudioFileSource (Session& s, std::string path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
+AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
: AudioSource (s, path), _flags (flags),
- channel (0)
+ _channel (0)
{
/* constructor used for new internal-to-session files. file cannot exist */
_is_embedded = false;
@@ -88,9 +89,9 @@ AudioFileSource::AudioFileSource (Session& s, std::string path, Flag flags, Samp
}
}
-AudioFileSource::AudioFileSource (Session& s, const XMLNode& node)
+AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
: AudioSource (s, node), _flags (Flag (Writable|CanRename))
- /* channel is set in set_state() */
+ /* _channel is set in set_state() */
{
/* constructor used for existing internal-to-session files. file must exist */
@@ -98,7 +99,7 @@ AudioFileSource::AudioFileSource (Session& s, const XMLNode& node)
throw failed_constructor ();
}
- if (init (_name, true)) {
+ if (init (_name, must_exist)) {
throw failed_constructor ();
}
}
@@ -112,7 +113,7 @@ AudioFileSource::~AudioFileSource ()
}
bool
-AudioFileSource::determine_embeddedness (std::string path)
+AudioFileSource::determine_embeddedness (ustring path)
{
return (path.find("/") == 0);
}
@@ -124,18 +125,17 @@ AudioFileSource::removable () const
}
int
-AudioFileSource::init (string pathstr, bool must_exist)
+AudioFileSource::init (ustring pathstr, bool must_exist)
{
bool is_new = false;
_length = 0;
timeline_position = 0;
- next_peak_clear_should_notify = false;
_peaks_built = false;
file_is_new = false;
if (!find (pathstr, must_exist, is_new)) {
- return -1;
+ throw non_existent_source ();
}
if (is_new && must_exist) {
@@ -146,40 +146,40 @@ AudioFileSource::init (string pathstr, bool must_exist)
}
-string
-AudioFileSource::peak_path (string audio_path)
+ustring
+AudioFileSource::peak_path (ustring audio_path)
{
return _session.peak_path_from_audio_path (audio_path);
}
-string
-AudioFileSource::old_peak_path (string audio_path)
+ustring
+AudioFileSource::old_peak_path (ustring audio_path)
{
/* XXX hardly bombproof! fix me */
struct stat stat_file;
struct stat stat_mount;
- string mp = mountpoint (audio_path);
+ ustring mp = mountpoint (audio_path);
stat (audio_path.c_str(), &stat_file);
stat (mp.c_str(), &stat_mount);
char buf[32];
#ifdef __APPLE__
- snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, channel);
+ snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
#else
- snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, channel);
+ snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
#endif
- string res = peak_dir;
+ ustring res = peak_dir;
res += buf;
return res;
}
bool
-AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
+AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
{
#ifdef HAVE_COREAUDIO
if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
@@ -200,7 +200,7 @@ AudioFileSource::get_state ()
XMLNode& root (AudioSource::get_state());
char buf[32];
root.add_property (X_("flags"), enum_2_string (_flags));
- snprintf (buf, sizeof (buf), "%d", channel);
+ snprintf (buf, sizeof (buf), "%u", _channel);
root.add_property (X_("channel"), buf);
return root;
}
@@ -222,9 +222,9 @@ AudioFileSource::set_state (const XMLNode& node)
}
if ((prop = node.property (X_("channel"))) != 0) {
- channel = atoi (prop->value());
+ _channel = atoi (prop->value());
} else {
- channel = 0;
+ _channel = 0;
}
if ((prop = node.property (X_("name"))) != 0) {
@@ -260,16 +260,13 @@ AudioFileSource::mark_streaming_write_completed ()
Glib::Mutex::Lock lm (_lock);
- next_peak_clear_should_notify = true;
-
- if (_peaks_built || pending_peak_builds.empty()) {
- _peaks_built = true;
+ if (_peaks_built) {
PeaksReady (); /* EMIT SIGNAL */
}
}
void
-AudioFileSource::mark_take (string id)
+AudioFileSource::mark_take (ustring id)
{
if (writable()) {
_take_id = id;
@@ -277,14 +274,14 @@ AudioFileSource::mark_take (string id)
}
int
-AudioFileSource::move_to_trash (const string trash_dir_name)
+AudioFileSource::move_to_trash (const ustring& trash_dir_name)
{
if (is_embedded()) {
cerr << "tried to move an embedded region to trash" << endl;
return -1;
}
- string newpath;
+ ustring newpath;
if (!writable()) {
return -1;
@@ -311,7 +308,7 @@ AudioFileSource::move_to_trash (const string trash_dir_name)
char buf[PATH_MAX+1];
int version = 1;
- string newpath_v;
+ ustring newpath_v;
snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
newpath_v = buf;
@@ -362,18 +359,16 @@ AudioFileSource::move_to_trash (const string trash_dir_name)
}
bool
-AudioFileSource::find (string pathstr, bool must_exist, bool& isnew)
+AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew)
{
- string::size_type pos;
+ ustring::size_type pos;
bool ret = false;
isnew = false;
/* clean up PATH:CHANNEL notation so that we are looking for the correct path */
- if ((pos = pathstr.find_last_of (':')) == string::npos) {
- pathstr = pathstr;
- } else {
+ if ((pos = pathstr.find_last_of (':')) != ustring::npos) {
pathstr = pathstr.substr (0, pos);
}
@@ -381,10 +376,10 @@ AudioFileSource::find (string pathstr, bool must_exist, bool& isnew)
/* non-absolute pathname: find pathstr in search path */
- vector<string> dirs;
+ vector<ustring> dirs;
int cnt;
- string fullpath;
- string keeppath;
+ ustring fullpath;
+ ustring keeppath;
if (search_path.length() == 0) {
error << _("FileSource: search path not set") << endmsg;
@@ -395,7 +390,7 @@ AudioFileSource::find (string pathstr, bool must_exist, bool& isnew)
cnt = 0;
- for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
+ for (vector<ustring>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
fullpath = *i;
if (fullpath[fullpath.length()-1] != '/') {
@@ -471,7 +466,7 @@ AudioFileSource::find (string pathstr, bool must_exist, bool& isnew)
}
void
-AudioFileSource::set_search_path (string p)
+AudioFileSource::set_search_path (ustring p)
{
search_path = p;
}
@@ -513,11 +508,11 @@ AudioFileSource::set_allow_remove_if_empty (bool yn)
}
int
-AudioFileSource::set_name (string newname, bool destructive)
+AudioFileSource::set_name (ustring newname, bool destructive)
{
Glib::Mutex::Lock lm (_lock);
- string oldpath = _path;
- string newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive);
+ ustring oldpath = _path;
+ ustring newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive);
if (newpath.empty()) {
error << string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg;
@@ -542,7 +537,7 @@ AudioFileSource::set_name (string newname, bool destructive)
}
bool
-AudioFileSource::is_empty (Session& s, string path)
+AudioFileSource::is_empty (Session& s, ustring path)
{
bool ret = false;
@@ -566,30 +561,36 @@ AudioFileSource::setup_peakfile ()
}
bool
-AudioFileSource::safe_file_extension(string file)
+AudioFileSource::safe_file_extension(ustring file)
{
- return !(file.rfind(".wav") == string::npos &&
- file.rfind(".aiff")== string::npos &&
- file.rfind(".aif") == string::npos &&
- file.rfind(".snd") == string::npos &&
- file.rfind(".au") == string::npos &&
- file.rfind(".raw") == string::npos &&
- file.rfind(".sf") == string::npos &&
- file.rfind(".cdr") == string::npos &&
- file.rfind(".smp") == string::npos &&
- file.rfind(".maud")== string::npos &&
- file.rfind(".vwe") == string::npos &&
- file.rfind(".paf") == string::npos &&
+ return !(file.rfind(".wav") == ustring::npos &&
+ file.rfind(".aiff")== ustring::npos &&
+ file.rfind(".aif") == ustring::npos &&
+ file.rfind(".snd") == ustring::npos &&
+ file.rfind(".au") == ustring::npos &&
+ file.rfind(".raw") == ustring::npos &&
+ file.rfind(".sf") == ustring::npos &&
+ file.rfind(".cdr") == ustring::npos &&
+ file.rfind(".smp") == ustring::npos &&
+ file.rfind(".maud")== ustring::npos &&
+ file.rfind(".vwe") == ustring::npos &&
+ file.rfind(".paf") == ustring::npos &&
#ifdef HAVE_COREAUDIO
- file.rfind(".mp3") == string::npos &&
- file.rfind(".aac") == string::npos &&
- file.rfind(".mp4") == string::npos &&
+ file.rfind(".mp3") == ustring::npos &&
+ file.rfind(".aac") == ustring::npos &&
+ file.rfind(".mp4") == ustring::npos &&
#endif // HAVE_COREAUDIO
- file.rfind(".voc") == string::npos);
+ file.rfind(".voc") == ustring::npos);
}
void
AudioFileSource::mark_immutable ()
{
- _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
+ /* destructive sources stay writable, and their other flags don't
+ change.
+ */
+
+ if (!(_flags & Destructive)) {
+ _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
+ }
}
diff --git a/libs/ardour/audiofilter.cc b/libs/ardour/audiofilter.cc
index 4c38ecec20..d4d59d4a60 100644
--- a/libs/ardour/audiofilter.cc
+++ b/libs/ardour/audiofilter.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <time.h>
@@ -80,6 +79,7 @@ AudioFilter::finish (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs)
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*si);
if (afs) {
afs->update_header (region->position(), *now, xnow);
+ afs->mark_immutable ();
}
}
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 38f8ed3652..8bb40e9bcb 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
@@ -41,7 +40,6 @@
#include <ardour/playlist.h>
#include <ardour/audiofilter.h>
#include <ardour/audiofilesource.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/region_factory.h>
#include "i18n.h"
@@ -932,10 +930,15 @@ AudioRegion::separate_by_channel (Session& session, vector<boost::shared_ptr<Aud
new_name += ('0' + n + 1);
}
- /* create a copy with just one source */
+ /* create a copy with just one source. prevent if from being thought of as "whole file" even if
+ it covers the entire source file(s).
+ */
+
+ Flag f = Flag (_flags & ~WholeFile);
- boost::shared_ptr<Region> r = RegionFactory::create (srcs, _start, _length, new_name, _layer, _flags);
+ boost::shared_ptr<Region> r = RegionFactory::create (srcs, _start, _length, new_name, _layer, f);
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
+ cerr << "new region name is " << ar->name() << endl;
v.push_back (ar);
@@ -1096,6 +1099,7 @@ AudioRegion::normalize_to (float target_dB)
boost::shared_ptr<Playlist> pl (playlist());
if (pl) {
+ cerr << "Send modified\n";
pl->Modified();
}
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index 203590a4e1..6fe2f67e05 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: source.cc 404 2006-03-17 17:39:21Z pauld $
*/
#include <sys/stat.h>
@@ -36,6 +35,7 @@
#include <ardour/audiosource.h>
#include <ardour/cycle_timer.h>
+#include <ardour/session.h>
#include "i18n.h"
@@ -43,41 +43,33 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-pthread_t AudioSource::peak_thread;
-bool AudioSource::have_peak_thread = false;
-vector<boost::shared_ptr<AudioSource> > AudioSource::pending_peak_sources;
-Glib::Mutex* AudioSource::pending_peak_sources_lock = 0;
-int AudioSource::peak_request_pipe[2];
-
bool AudioSource::_build_missing_peakfiles = false;
bool AudioSource::_build_peakfiles = false;
-AudioSource::AudioSource (Session& s, string name)
+AudioSource::AudioSource (Session& s, ustring name)
: Source (s, name, DataType::AUDIO)
{
- if (pending_peak_sources_lock == 0) {
- pending_peak_sources_lock = new Glib::Mutex;
- }
-
_peaks_built = false;
_peak_byte_max = 0;
- next_peak_clear_should_notify = true;
+ peakfile = -1;
_read_data_count = 0;
_write_data_count = 0;
+ peak_leftover_cnt = 0;
+ peak_leftover_size = 0;
+ peak_leftovers = 0;
}
AudioSource::AudioSource (Session& s, const XMLNode& node)
: Source (s, node)
{
- if (pending_peak_sources_lock == 0) {
- pending_peak_sources_lock = new Glib::Mutex;
- }
-
_peaks_built = false;
_peak_byte_max = 0;
- next_peak_clear_should_notify = true;
+ peakfile = -1;
_read_data_count = 0;
_write_data_count = 0;
+ peak_leftover_cnt = 0;
+ peak_leftover_size = 0;
+ peak_leftovers = 0;
if (set_state (node)) {
throw failed_constructor();
@@ -86,6 +78,19 @@ AudioSource::AudioSource (Session& s, const XMLNode& node)
AudioSource::~AudioSource ()
{
+ /* shouldn't happen but make sure we don't leak file descriptors anyway */
+
+ if (peak_leftover_cnt) {
+ cerr << "AudioSource destroyed with leftover peak data pending" << endl;
+ }
+
+ if (peakfile >= 0) {
+ ::close (peakfile);
+ }
+
+ if (peak_leftovers) {
+ delete [] peak_leftovers;
+ }
}
XMLNode&
@@ -118,171 +123,6 @@ AudioSource::set_state (const XMLNode& node)
PEAK FILE STUFF
***********************************************************************/
-void*
-AudioSource::peak_thread_work (void* arg)
-{
- PBD::ThreadCreated (pthread_self(), X_("Peak"));
- struct pollfd pfd[1];
-
- if (pending_peak_sources_lock == 0) {
- pending_peak_sources_lock = new Glib::Mutex;
- }
-
- Glib::Mutex::Lock lm (*pending_peak_sources_lock);
-
- while (true) {
-
- pfd[0].fd = peak_request_pipe[0];
- pfd[0].events = POLLIN|POLLERR|POLLHUP;
-
- pending_peak_sources_lock->unlock ();
-
- if (poll (pfd, 1, -1) < 0) {
-
- if (errno == EINTR) {
- pending_peak_sources_lock->lock ();
- continue;
- }
-
- error << string_compose (_("poll on peak request pipe failed (%1)"),
- strerror (errno))
- << endmsg;
- break;
- }
-
- if (pfd[0].revents & ~POLLIN) {
- error << _("Error on peak thread request pipe") << endmsg;
- break;
- }
-
- if (pfd[0].revents & POLLIN) {
-
- char req;
-
- /* empty the pipe of all current requests */
-
- while (1) {
- size_t nread = ::read (peak_request_pipe[0], &req, sizeof (req));
-
- if (nread == 1) {
- switch ((PeakRequest::Type) req) {
-
- case PeakRequest::Build:
- break;
-
- case PeakRequest::Quit:
- pthread_exit_pbd (0);
- /*NOTREACHED*/
- break;
-
- default:
- break;
- }
-
- } else if (nread == 0) {
- break;
- } else if (errno == EAGAIN) {
- break;
- } else {
- fatal << _("Error reading from peak request pipe") << endmsg;
- /*NOTREACHED*/
- }
- }
- }
-
- pending_peak_sources_lock->lock ();
-
- while (!pending_peak_sources.empty()) {
-
- boost::shared_ptr<AudioSource> s = pending_peak_sources.front();
- pending_peak_sources.erase (pending_peak_sources.begin());
-
- pending_peak_sources_lock->unlock ();
- s->build_peaks();
- pending_peak_sources_lock->lock ();
- }
- }
-
- pthread_exit_pbd (0);
- /*NOTREACHED*/
- return 0;
-}
-
-int
-AudioSource::start_peak_thread ()
-{
- if (!_build_peakfiles) {
- return 0;
- }
-
- if (pipe (peak_request_pipe)) {
- error << string_compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg;
- return -1;
- }
-
- if (fcntl (peak_request_pipe[0], F_SETFL, O_NONBLOCK)) {
- error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
- return -1;
- }
-
- if (fcntl (peak_request_pipe[1], F_SETFL, O_NONBLOCK)) {
- error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg;
- return -1;
- }
-
- if (pthread_create_and_store ("peak file builder", &peak_thread, 0, peak_thread_work, 0)) {
- error << _("AudioSource: could not create peak thread") << endmsg;
- return -1;
- }
-
- have_peak_thread = true;
- return 0;
-}
-
-void
-AudioSource::stop_peak_thread ()
-{
- if (!have_peak_thread) {
- return;
- }
-
- void* status;
-
- char c = (char) PeakRequest::Quit;
- ::write (peak_request_pipe[1], &c, 1);
- pthread_join (peak_thread, &status);
-}
-
-void
-AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source, bool notify)
-{
- if (have_peak_thread) {
-
- Glib::Mutex::Lock lm (*pending_peak_sources_lock);
-
- source->next_peak_clear_should_notify = notify;
-
- if (find (pending_peak_sources.begin(),
- pending_peak_sources.end(),
- source) == pending_peak_sources.end()) {
- pending_peak_sources.push_back (source);
- }
-
- char c = (char) PeakRequest::Build;
- ::write (peak_request_pipe[1], &c, 1);
- }
-}
-
-void AudioSource::clear_queue_for_peaks ()
-{
- /* this is done to cancel a group of running peak builds */
- if (have_peak_thread) {
- Glib::Mutex::Lock lm (*pending_peak_sources_lock);
- pending_peak_sources.clear ();
- }
-}
-
-
bool
AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
{
@@ -318,11 +158,11 @@ AudioSource::touch_peakfile ()
}
int
-AudioSource::rename_peakfile (string newpath)
+AudioSource::rename_peakfile (ustring newpath)
{
/* caller must hold _lock */
- string oldpath = peakpath;
+ ustring oldpath = peakpath;
if (access (oldpath.c_str(), F_OK) == 0) {
if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
@@ -337,7 +177,7 @@ AudioSource::rename_peakfile (string newpath)
}
int
-AudioSource::initialize_peakfile (bool newfile, string audio_path)
+AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
{
struct stat statbuf;
@@ -348,7 +188,7 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path)
*/
if (!newfile && access (peakpath.c_str(), R_OK) != 0) {
- string str = old_peak_path (audio_path);
+ ustring str = old_peak_path (audio_path);
if (access (str.c_str(), R_OK) == 0) {
peakpath = str;
}
@@ -431,7 +271,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
int ret = -1;
PeakData* staging = 0;
Sample* raw_staging = 0;
- int peakfile = -1;
+ int _peakfile = -1;
expected_peaks = (cnt / (double) frames_per_peak);
scale = npeaks/expected_peaks;
@@ -492,7 +332,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open, read, close */
- if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
+ if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
}
@@ -501,8 +341,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
cerr << "DIRECT PEAKS\n";
#endif
- nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
- close (peakfile);
+ nread = ::pread (_peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
+ close (_peakfile);
if (nread != sizeof (PeakData) * npeaks) {
cerr << "AudioSource["
@@ -566,7 +406,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open ... close during out: handling */
- if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
+ if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return 0;
}
@@ -583,10 +423,10 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
#endif
- if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte))
+ if ((nread = ::pread (_peakfile, staging, sizeof (PeakData) * to_read, start_byte))
!= sizeof (PeakData) * to_read) {
- off_t fend = lseek (peakfile, 0, SEEK_END);
+ off_t fend = lseek (_peakfile, 0, SEEK_END);
cerr << "AudioSource["
<< _name
@@ -672,13 +512,21 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
to_read = min (chunksize, (_length - current_frame));
+ if (to_read == 0) {
+ /* XXX ARGH .. out by one error ... need to figure out why this happens
+ and fix it rather than do this band-aid move.
+ */
+ zero_fill = npeaks - nvisual_peaks;
+ break;
+ }
+
if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
- error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3")
- , _name, to_read, current_frame)
+ error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3 of %4 (%5)"),
+ _name, to_read, current_frame, _length, strerror (errno))
<< endmsg;
goto out;
}
-
+
i = 0;
}
@@ -708,8 +556,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
}
out:
- if (peakfile >= 0) {
- close (peakfile);
+ if (_peakfile >= 0) {
+ close (_peakfile);
}
if (staging) {
@@ -730,196 +578,277 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
#undef DEBUG_PEAK_BUILD
int
-AudioSource::build_peaks ()
+AudioSource::build_peaks_from_scratch ()
{
- vector<PeakBuildRecord*> built;
- int status = -1;
- bool pr_signal = false;
- list<PeakBuildRecord*> copy;
+ nframes_t current_frame;
+ nframes_t cnt;
+ Sample buf[frames_per_peak];
+ nframes_t frames_read;
+ nframes_t frames_to_read;
+ int ret = -1;
{
- Glib::Mutex::Lock lm (_lock);
- copy = pending_peak_builds;
- pending_peak_builds.clear ();
- }
-
-#ifdef DEBUG_PEAK_BUILD
- cerr << "build peaks with " << copy.size() << " requests pending\n";
-#endif
+ /* hold lock while building peaks */
- for (list<PeakBuildRecord *>::iterator i = copy.begin(); i != copy.end(); ++i) {
+ Glib::Mutex::Lock lp (_lock);
- if ((status = do_build_peak ((*i)->frame, (*i)->cnt)) != 0) {
- unlink (peakpath.c_str());
- break;
+ if (prepare_for_peakfile_writes ()) {
+ goto out;
}
- built.push_back (new PeakBuildRecord (*(*i)));
- delete *i;
- }
+
+ current_frame = 0;
+ cnt = _length;
+ _peaks_built = false;
+
+ while (cnt) {
+
+ frames_to_read = min (frames_per_peak, cnt);
- {
- Glib::Mutex::Lock lm (_lock);
+ if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
+ error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
+ done_with_peakfile_writes ();
+ goto out;
+ }
- if (status == 0) {
- _peaks_built = true;
-
- if (next_peak_clear_should_notify) {
- next_peak_clear_should_notify = false;
- pr_signal = true;
+ if (compute_and_write_peaks (buf, current_frame, frames_read, true)) {
+ break;
}
+
+ current_frame += frames_read;
+ cnt -= frames_read;
}
+
+ if (cnt == 0) {
+ /* success */
+ truncate_peakfile();
+ _peaks_built = true;
+ }
+
+ done_with_peakfile_writes ();
}
- if (status == 0) {
- for (vector<PeakBuildRecord *>::iterator i = built.begin(); i != built.end(); ++i) {
- PeakRangeReady ((*i)->frame, (*i)->cnt); /* EMIT SIGNAL */
- delete *i;
- }
+ /* lock no longer held, safe to signal */
- if (pr_signal) {
- truncate_peakfile();
- PeaksReady (); /* EMIT SIGNAL */
- }
+ if (_peaks_built) {
+ PeaksReady (); /* EMIT SIGNAL */
+ ret = 0;
+ }
+
+ out:
+ if (ret) {
+ unlink (peakpath.c_str());
}
- return status;
+ return ret;
}
int
-AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt)
+AudioSource::prepare_for_peakfile_writes ()
{
+ if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
+ error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+ return -1;
+ }
+ return 0;
+}
+
+void
+AudioSource::done_with_peakfile_writes ()
+{
+ if (peak_leftover_cnt) {
+ compute_and_write_peaks (0, 0, 0, true);
+ }
+
+ if (peakfile >= 0) {
+ close (peakfile);
+ peakfile = -1;
+ }
+}
+
+int
+AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force)
+{
+ Sample* buf2 = 0;
+ nframes_t to_do;
+ uint32_t peaks_computed;
+ PeakData* peakbuf = 0;
+ int ret = -1;
nframes_t current_frame;
- Sample buf[frames_per_peak];
- Sample xmin, xmax;
- uint32_t peaki;
- PeakData* peakbuf;
- nframes_t frames_read;
- nframes_t frames_to_read;
+ nframes_t frames_done;
+ const size_t blocksize = (128 * 1024);
off_t first_peak_byte;
- int peakfile = -1;
- int ret = -1;
- off_t target_length;
- off_t endpos;
-#ifdef DEBUG_PEAK_BUILD
- cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl;
-#endif
+ if (peakfile < 0) {
+ prepare_for_peakfile_writes ();
+ }
- first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
+ restart:
+ if (peak_leftover_cnt) {
-#ifdef DEBUG_PEAK_BUILD
- cerr << "seeking to " << first_peak_byte << " before writing new peak data\n";
-#endif
+ if (first_frame != peak_leftover_frame + peak_leftover_cnt) {
- current_frame = first_frame;
- peakbuf = new PeakData[(cnt/frames_per_peak)+1];
- peaki = 0;
+ /* uh-oh, ::seek() since the last ::compute_and_write_peaks(),
+ and we have leftovers. flush a single peak (since the leftovers
+ never represent more than that, and restart.
+ */
+
+ PeakData x;
+
+ x.min = peak_leftovers[0];
+ x.max = peak_leftovers[0];
+ Session::find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max);
- if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
- error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
- return -1;
- }
-
- while (cnt) {
+ off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData);
- frames_to_read = min (frames_per_peak, cnt);
+ if (::pwrite (peakfile, &x, sizeof (PeakData), byte) != sizeof (PeakData)) {
+ error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
+ goto out;
+ }
- /* lock for every read */
+ _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
- if ((frames_read = read (buf, current_frame, frames_to_read)) != frames_to_read) {
- error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
- goto out;
+ PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
+ PeaksReady (); /* EMIT SIGNAL */
+
+ /* left overs are done */
+
+ peak_leftover_cnt = 0;
+ goto restart;
}
- xmin = buf[0];
- xmax = buf[0];
+ /* else ... had leftovers, but they immediately preceed the new data, so just
+ merge them and compute.
+ */
+
+ /* make a new contiguous buffer containing leftovers and the new stuff */
- for (nframes_t n = 1; n < frames_read; ++n) {
- xmax = max (xmax, buf[n]);
- xmin = min (xmin, buf[n]);
+ to_do = cnt + peak_leftover_cnt;
+ buf2 = new Sample[to_do];
-// if (current_frame < frames_read) {
-// cerr << "sample = " << buf[n] << " max = " << xmax << " min = " << xmin << " max of 2 = " << max (xmax, buf[n]) << endl;
-// }
- }
+ /* the remnants */
+ memcpy (buf2, peak_leftovers, peak_leftover_cnt * sizeof (Sample));
+
+ /* the new stuff */
+ memcpy (buf2+peak_leftover_cnt, buf, cnt * sizeof (Sample));
+
+ /* no more leftovers */
+ peak_leftover_cnt = 0;
+
+ /* use the temporary buffer */
+ buf = buf2;
- peakbuf[peaki].max = xmax;
- peakbuf[peaki].min = xmin;
- peaki++;
+ /* make sure that when we write into the peakfile, we startup where we left off */
- current_frame += frames_read;
- cnt -= frames_read;
+ first_frame = peak_leftover_frame;
+
+ } else {
+ to_do = cnt;
}
-#define BLOCKSIZE (128 * 1024)
+ peakbuf = new PeakData[(to_do/frames_per_peak)+1];
+ peaks_computed = 0;
+ current_frame = first_frame;
+ frames_done = 0;
- /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
- the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
- it does not cause single-extent allocation even for peakfiles of
- less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
- */
- endpos = lseek (peakfile, 0, SEEK_END);
+ while (to_do) {
+
+ /* if some frames were passed in (i.e. we're not flushing leftovers)
+ and there are less than frames_per_peak to do, save them till
+ next time
+ */
+
+ if (force && (to_do < frames_per_peak)) {
+ /* keep the left overs around for next time */
+
+ if (peak_leftover_size < to_do) {
+ delete [] peak_leftovers;
+ peak_leftovers = new Sample[to_do];
+ peak_leftover_size = to_do;
+ }
+ memcpy (peak_leftovers, buf, to_do * sizeof (Sample));
+ peak_leftover_cnt = to_do;
+ peak_leftover_frame = current_frame;
+
+ /* done for now */
+
+ break;
+ }
+
+ nframes_t this_time = min (frames_per_peak, to_do);
+
+ peakbuf[peaks_computed].max = buf[0];
+ peakbuf[peaks_computed].min = buf[0];
+
+ Session::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
+
+ peaks_computed++;
+ buf += this_time;
+ to_do -= this_time;
+ frames_done += this_time;
+ current_frame += this_time;
+ }
- target_length = BLOCKSIZE * ((first_peak_byte + BLOCKSIZE + 1) / BLOCKSIZE);
+ first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData);
- if (endpos < target_length) {
- // XXX - we really shouldn't be doing this for destructive source peaks
- ftruncate (peakfile, target_length);
- //cerr << "do build TRUNC: " << peakpath << " " << target_length << endl;
+ if (can_truncate_peaks()) {
- /* error doesn't actually matter though, so continue on without testing */
+ /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
+ the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
+ it does not cause single-extent allocation even for peakfiles of
+ less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
+ */
+
+ off_t endpos = lseek (peakfile, 0, SEEK_END);
+ off_t target_length = blocksize * ((first_peak_byte + blocksize + 1) / blocksize);
+
+ if (endpos < target_length) {
+ ftruncate (peakfile, target_length);
+ /* error doesn't actually matter though, so continue on without testing */
+ }
}
- if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) {
+ if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaks_computed, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaks_computed)) {
error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
goto out;
}
- _peak_byte_max = max(_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaki));
+ _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
+
+ if (frames_done) {
+ PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
+ PeaksReady (); /* EMIT SIGNAL */
+ }
ret = 0;
out:
delete [] peakbuf;
- if (peakfile >= 0) {
- close (peakfile);
+ if (buf2) {
+ delete [] buf2;
}
return ret;
}
void
-AudioSource::build_peaks_from_scratch ()
-{
- Glib::Mutex::Lock lp (_lock);
-
- next_peak_clear_should_notify = true;
- pending_peak_builds.push_back (new PeakBuildRecord (0, _length));
- queue_for_peaks (shared_from_this(), true);
-}
-
-void
AudioSource::truncate_peakfile ()
{
- int peakfile = -1;
+ if (peakfile < 0) {
+ error << string_compose (_("programming error: %1"), "AudioSource::truncate_peakfile() called without open peakfile descriptor")
+ << endmsg;
+ return;
+ }
/* truncate the peakfile down to its natural length if necessary */
- if ((peakfile = ::open (peakpath.c_str(), O_RDWR)) >= 0) {
- off_t end = lseek (peakfile, 0, SEEK_END);
-
- if (end > _peak_byte_max) {
- ftruncate(peakfile, _peak_byte_max);
- //cerr << "truncated " << peakpath << " to " << _peak_byte_max << " bytes" << endl;
- }
- else {
- //cerr << "NOT truncated " << peakpath << " to " << _peak_byte_max << " end " << end << endl;
- }
- close (peakfile);
+ off_t end = lseek (peakfile, 0, SEEK_END);
+
+ if (end > _peak_byte_max) {
+ ftruncate (peakfile, _peak_byte_max);
}
}
bool
-AudioSource::file_changed (string path)
+AudioSource::file_changed (ustring path)
{
struct stat stat_file;
struct stat stat_peak;
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index 7bbc4cd0ba..0ba30b2b8b 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <glibmm/thread.h>
@@ -65,7 +64,7 @@ Auditioner::Auditioner (Session& s)
}
if (right.length()) {
- audio_diskstream()->add_channel();
+ audio_diskstream()->add_channel (1);
add_output_port (right, this, DataType::AUDIO);
}
@@ -141,12 +140,10 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
_diskstream->playlist()->clear ();
_diskstream->playlist()->add_region (the_region, 0, 1);
- while (_diskstream->n_channels().get(DataType::AUDIO) < the_region->n_channels()) {
- audio_diskstream()->add_channel ();
- }
-
- while (_diskstream->n_channels().get(DataType::AUDIO) > the_region->n_channels()) {
- audio_diskstream()->remove_channel ();
+ if (_diskstream->n_channels().get(DataType::AUDIO) < the_region->n_channels()) {
+ audio_diskstream()->add_channel (the_region->n_channels() - _diskstream->n_channels().get(DataType::AUDIO));
+ } else if (_diskstream->n_channels().get(DataType::AUDIO) > the_region->n_channels()) {
+ audio_diskstream()->remove_channel (_diskstream->n_channels().get(DataType::AUDIO) - the_region->n_channels());
}
/* force a panner reset now that we have all channels */
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index af6fffdeb9..341fa82091 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <set>
diff --git a/libs/ardour/buffer.cc b/libs/ardour/buffer.cc
index d4a370685c..f13aa82207 100644
--- a/libs/ardour/buffer.cc
+++ b/libs/ardour/buffer.cc
@@ -22,6 +22,12 @@ using std::cerr; using std::endl;
#include <ardour/buffer.h>
+#ifdef __x86_64__
+static const int CPU_CACHE_ALIGN = 64;
+#else
+static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
+#endif
+
namespace ARDOUR {
@@ -47,7 +53,7 @@ AudioBuffer::AudioBuffer(size_t capacity)
#ifdef NO_POSIX_MEMALIGN
_data = (Sample *) malloc(sizeof(Sample) * capacity);
#else
- posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity);
+ posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Sample) * capacity);
#endif
assert(_data);
_owns_data = true;
@@ -76,8 +82,8 @@ MidiBuffer::MidiBuffer(size_t capacity)
_events = (MidiEvent *) malloc(sizeof(MidiEvent) * capacity);
_data = (RawMidi *) malloc(sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
#else
- posix_memalign((void**)&_events, 16, sizeof(MidiEvent) * capacity);
- posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
+ posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MidiEvent) * capacity);
+ posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
#endif
assert(_data);
assert(_events);
diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc
index a0f2b5e036..c8d71c5155 100644
--- a/libs/ardour/configuration.cc
+++ b/libs/ardour/configuration.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <unistd.h>
@@ -27,7 +26,6 @@
#include <ardour/ardour.h>
#include <ardour/configuration.h>
#include <ardour/audio_diskstream.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/control_protocol_manager.h>
#include "i18n.h"
@@ -318,6 +316,22 @@ Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
#undef CONFIG_VARIABLE_SPECIAL
}
+bool ConfigVariableBase::show_stores = false;
+
+void
+ConfigVariableBase::set_show_stored_values (bool yn)
+{
+ show_stores = yn;
+}
+
+void
+ConfigVariableBase::show_stored_value (const string& str)
+{
+ if (show_stores) {
+ cerr << "Config variable " << _name << " stored as " << str << endl;
+ }
+}
+
void
ConfigVariableBase::notify ()
{
@@ -330,3 +344,4 @@ ConfigVariableBase::miss ()
// placeholder for any debugging desired when a config variable
// is set but to the same value as it already has
}
+
diff --git a/libs/ardour/connection.cc b/libs/ardour/connection.cc
index fbfd02d509..13b7dc4ddb 100644
--- a/libs/ardour/connection.cc
+++ b/libs/ardour/connection.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc
index 72f56794d7..899790dddc 100644
--- a/libs/ardour/control_protocol_manager.cc
+++ b/libs/ardour/control_protocol_manager.cc
@@ -43,7 +43,6 @@ ControlProtocolManager::~ControlProtocolManager()
}
control_protocol_info.clear();
-
}
void
@@ -75,12 +74,11 @@ ControlProtocolManager::drop_session ()
delete *p;
}
control_protocols.clear ();
-
+
for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
- delete *p;
+ // otherwise the ControlProtocol instances are not recreated in set_session
+ (*p)->requested = true;
}
-
- control_protocol_info.clear();
}
}
@@ -106,10 +104,6 @@ ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
Glib::Mutex::Lock lm (protocols_lock);
control_protocols.push_back (cpi.protocol);
- if (cpi.state) {
- cpi.protocol->set_state (*cpi.state);
- }
-
return cpi.protocol;
}
@@ -297,7 +291,6 @@ ControlProtocolManager::set_state (const XMLNode& node)
if ((prop = (*citer)->property (X_("name"))) != 0) {
ControlProtocolInfo* cpi = cpi_by_name (prop->value());
if (cpi) {
-
if (!(*citer)->children().empty()) {
cpi->state = (*citer)->children().front ();
} else {
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 66d1e099da..d75758dfb0 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <sigc++/bind.h>
diff --git a/libs/ardour/curve.cc b/libs/ardour/curve.cc
index 8465094775..5a1dc108f8 100644
--- a/libs/ardour/curve.cc
+++ b/libs/ardour/curve.cc
@@ -18,7 +18,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <iostream>
diff --git a/libs/ardour/cycle_timer.cc b/libs/ardour/cycle_timer.cc
index 3031d5a7ec..143cb841ec 100644
--- a/libs/ardour/cycle_timer.cc
+++ b/libs/ardour/cycle_timer.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cstdio>
diff --git a/libs/ardour/default_click.cc b/libs/ardour/default_click.cc
index b4067a2051..5bdbeb2ac5 100644
--- a/libs/ardour/default_click.cc
+++ b/libs/ardour/default_click.cc
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <ardour/ardour.h>
diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc
deleted file mode 100644
index 5eada195cd..0000000000
--- a/libs/ardour/destructive_filesource.cc
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- 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$
-*/
-
-/* This is is very hacky way to get pread and pwrite declarations.
- First, include <features.h> so that we can avoid its #undef __USE_UNIX98.
- Then define __USE_UNIX98, include <unistd.h>, and then undef it
- again. If #define _XOPEN_SOURCE actually worked, I'd use that, but
- despite claims in the header that it does, it doesn't.
-
- features.h isn't available on osx and it compiles fine without it.
-*/
-
-#ifdef HAVE_FEATURES_H
-#include <features.h>
-#endif
-
-#if __GNUC__ >= 3
-// #define _XOPEN_SOURCE 500
-#include <unistd.h>
-#else
-#define __USE_UNIX98
-#include <unistd.h>
-#undef __USE_UNIX98
-#endif
-
-// darwin supports 64 by default and doesn't provide wrapper functions.
-#if defined (__APPLE__)
-typedef off_t off64_t;
-#define open64 open
-#define close64 close
-#define lseek64 lseek
-#define pread64 pread
-#define pwrite64 pwrite
-#endif
-
-#include <errno.h>
-#include <cmath>
-#include <fcntl.h>
-
-#include <pbd/error.h>
-#include <pbd/stacktrace.h>
-#include <ardour/destructive_filesource.h>
-#include <ardour/utils.h>
-#include <ardour/session.h>
-
-#include "i18n.h"
-
-using namespace std;
-using namespace ARDOUR;
-using namespace PBD;
-
-gain_t* DestructiveFileSource::out_coefficient = 0;
-gain_t* DestructiveFileSource::in_coefficient = 0;
-nframes_t DestructiveFileSource::xfade_frames = 64;
-
-DestructiveFileSource::DestructiveFileSource (Session& s, string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, Flag flags)
- : SndFileSource (s, path, samp_format, hdr_format, rate, flags)
-{
- init ();
-}
-
-
-DestructiveFileSource::DestructiveFileSource (Session& s, string path, Flag flags)
- : SndFileSource (s, path, flags)
-{
- init ();
-}
-
-DestructiveFileSource::DestructiveFileSource (Session& s, const XMLNode& node)
- : SndFileSource (s, 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()
-{
- delete xfade_buf;
-}
-
-void
-DestructiveFileSource::setup_standard_crossfades (nframes_t rate)
-{
- /* This static method is assumed to have been called by the Session
- before any DFS's are created.
- */
-
- xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
-
- if (out_coefficient) {
- delete [] out_coefficient;
- }
-
- if (in_coefficient) {
- delete [] in_coefficient;
- }
-
- out_coefficient = new gain_t[xfade_frames];
- in_coefficient = new gain_t[xfade_frames];
-
- compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
-}
-
-void
-DestructiveFileSource::mark_capture_start (nframes_t pos)
-{
- if (pos < timeline_position) {
- _capture_start = false;
- } else {
- _capture_start = true;
- capture_start_frame = pos;
- }
-}
-
-void
-DestructiveFileSource::mark_capture_end()
-{
- _capture_end = true;
-}
-
-void
-DestructiveFileSource::clear_capture_marks ()
-{
- _capture_start = false;
- _capture_end = false;
-}
-
-nframes_t
-DestructiveFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
-{
- nframes_t xfade = min (xfade_frames, cnt);
- nframes_t nofade = cnt - xfade;
- Sample* fade_data = 0;
- nframes_t fade_position = 0; // in frames
- ssize_t retval;
- nframes_t file_cnt;
-
- if (fade_in) {
- fade_position = file_pos;
- fade_data = data;
- } else {
- fade_position = file_pos + nofade;
- fade_data = data + nofade;
- }
-
- if (fade_position > _length) {
-
- /* read starts beyond end of data, just memset to zero */
-
- file_cnt = 0;
-
- } else if (fade_position + xfade > _length) {
-
- /* read ends beyond end of data, read some, memset the rest */
-
- file_cnt = _length - fade_position;
-
- } else {
-
- /* read is entirely within data */
-
- file_cnt = xfade;
- }
-
- if (file_cnt) {
-
- if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
- if (retval >= 0 && errno == EAGAIN) {
- /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
- * short or no data there */
- memset (xfade_buf, 0, xfade * sizeof(Sample));
- } else {
- error << string_compose(_("DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
- return 0;
- }
- }
- }
-
- if (file_cnt != xfade) {
- nframes_t delta = xfade - file_cnt;
- memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
- }
-
- if (nofade && !fade_in) {
- if (write_float (data, file_pos, nofade) != nofade) {
- error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
- return 0;
- }
- }
-
- if (xfade == xfade_frames) {
-
- nframes_t n;
-
- /* use the standard xfade curve */
-
- if (fade_in) {
-
- /* fade new material in */
-
- for (n = 0; n < xfade; ++n) {
- xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
- }
-
- } else {
-
-
- /* fade new material out */
-
- for (n = 0; n < xfade; ++n) {
- xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
- }
- }
-
- } else if (xfade) {
-
- gain_t in[xfade];
- gain_t out[xfade];
-
- /* short xfade, compute custom curve */
-
- compute_equal_power_fades (xfade, in, out);
-
- for (nframes_t n = 0; n < xfade; ++n) {
- xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
- }
- }
-
- if (xfade) {
- if (write_float (xfade_buf, fade_position, xfade) != xfade) {
- error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
- return 0;
- }
- }
-
- if (fade_in && nofade) {
- if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
- error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
- return 0;
- }
- }
-
- return cnt;
-}
-
-nframes_t
-DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt)
-{
- nframes_t old_file_pos;
-
- if (!writable()) {
- return 0;
- }
-
- 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;
-
- /* move to the correct location place */
- file_pos = capture_start_frame - timeline_position;
-
- // split cnt in half
- nframes_t subcnt = cnt / 2;
- nframes_t ofilepos = file_pos;
-
- // fade in
- if (crossfade (data, subcnt, 1) != subcnt) {
- return 0;
- }
-
- file_pos += subcnt;
- Sample * tmpdata = data + subcnt;
-
- // fade out
- subcnt = cnt - subcnt;
- if (crossfade (tmpdata, subcnt, 0) != subcnt) {
- return 0;
- }
-
- file_pos = ofilepos; // adjusted below
-
- } 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;
-
- /* move to the correct location place */
- file_pos = capture_start_frame - timeline_position;
-
- if (crossfade (data, cnt, 1) != cnt) {
- return 0;
- }
-
- } 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;
-
- if (crossfade (data, cnt, 0) != cnt) {
- return 0;
- }
-
- } else {
-
- /* in the middle of recording */
-
- if (write_float (data, file_pos, cnt) != cnt) {
- return 0;
- }
- }
-
- old_file_pos = file_pos;
- update_length (file_pos, cnt);
- file_pos += cnt;
-
- if (_build_peakfiles) {
- PeakBuildRecord *pbr = 0;
-
- if (pending_peak_builds.size()) {
- pbr = pending_peak_builds.back();
- }
-
- if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
-
- /* the last PBR extended to the start of the current write,
- so just extend it again.
- */
-
- pbr->cnt += cnt;
- } else {
- pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
- }
-
- _peaks_built = false;
- }
-
- if (_build_peakfiles) {
- queue_for_peaks (shared_from_this ());
- }
-
- return cnt;
-}
-
-nframes_t
-DestructiveFileSource::last_capture_start_frame () const
-{
- return capture_start_frame;
-}
-
-XMLNode&
-DestructiveFileSource::get_state ()
-{
- XMLNode& node = AudioFileSource::get_state ();
- node.add_property (X_("destructive"), "true");
- return node;
-}
-
-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 (int64_t pos)
-{
- //destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes
-}
-
-int
-DestructiveFileSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const
-{
- // cerr << _name << " read peaks at " << start << " for " << cnt << " tpos = " << timeline_position << endl;
- return AudioFileSource::read_peaks (peaks, npeaks, start, cnt, samples_per_unit);
-}
-
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index 09c5b75b86..c8fd2e48bf 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -15,7 +15,6 @@
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>
@@ -45,7 +44,6 @@
#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>
@@ -125,9 +123,6 @@ Diskstream::init (Flag f)
Diskstream::~Diskstream ()
{
- // Taken by derived class destrctors.. should assure locked here somehow?
- //Glib::Mutex::Lock lm (state_lock);
-
if (_playlist)
_playlist->release ();
}
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index 0460df43d8..4220adf7eb 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -31,6 +31,7 @@ setup_enum_writer ()
RegionPoint _RegionPoint;
Placement _Placement;
MonitorModel _MonitorModel;
+ RemoteModel _RemoteModel;
CrossfadeModel _CrossfadeModel;
LayerModel _LayerModel;
SoloModel _SoloModel;
@@ -142,6 +143,11 @@ setup_enum_writer ()
REGISTER_ENUM (ExternalMonitoring);
REGISTER (_MonitorModel);
+ REGISTER_ENUM (UserOrdered);
+ REGISTER_ENUM (MixerOrdered);
+ REGISTER_ENUM (EditorOrdered);
+ REGISTER (_RemoteModel);
+
REGISTER_ENUM (FullCrossfade);
REGISTER_ENUM (ShortCrossfade);
REGISTER (_CrossfadeModel);
diff --git a/libs/ardour/gain.cc b/libs/ardour/gain.cc
index 0b77bea279..369df7348c 100644
--- a/libs/ardour/gain.cc
+++ b/libs/ardour/gain.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <ardour/gain.h>
diff --git a/libs/ardour/gdither.cc b/libs/ardour/gdither.cc
index ec6bfaa2ea..7242f857c8 100644
--- a/libs/ardour/gdither.cc
+++ b/libs/ardour/gdither.cc
@@ -15,7 +15,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id$
*/
#include <ardour/gdither_types_internal.h>
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 549f4b7dbb..f5e841f00f 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -235,6 +235,7 @@ setup_hardware_optimization (bool try_optimization)
// SSE SET
Session::compute_peak = x86_sse_compute_peak;
+ Session::find_peaks = x86_sse_find_peaks;
Session::apply_gain_to_buffer = x86_sse_apply_gain_to_buffer;
Session::mix_buffers_with_gain = x86_sse_mix_buffers_with_gain;
Session::mix_buffers_no_gain = x86_sse_mix_buffers_no_gain;
@@ -251,6 +252,7 @@ setup_hardware_optimization (bool try_optimization)
if (sysVersion >= 0x00001040) { // Tiger at least
Session::compute_peak = veclib_compute_peak;
+ Session::find_peaks = veclib_find_peaks;
Session::apply_gain_to_buffer = veclib_apply_gain_to_buffer;
Session::mix_buffers_with_gain = veclib_mix_buffers_with_gain;
Session::mix_buffers_no_gain = veclib_mix_buffers_no_gain;
@@ -264,7 +266,8 @@ setup_hardware_optimization (bool try_optimization)
if (generic_mix_functions) {
- Session::compute_peak = compute_peak;
+ Session::compute_peak = compute_peak;
+ Session::find_peaks = find_peaks;
Session::apply_gain_to_buffer = apply_gain_to_buffer;
Session::mix_buffers_with_gain = mix_buffers_with_gain;
Session::mix_buffers_no_gain = mix_buffers_no_gain;
@@ -280,8 +283,6 @@ ARDOUR::init (ARDOUR::AudioEngine& engine, bool use_vst, bool try_optimization)
(void) bindtextdomain(PACKAGE, LOCALEDIR);
- PBD::ID::init ();
-
setup_enum_writer ();
lrdf_init();
@@ -617,6 +618,7 @@ std::istream& operator>>(std::istream& o, HeaderFormat& var) { return int_to_typ
std::istream& operator>>(std::istream& o, SampleFormat& var) { return int_to_type<SampleFormat> (o, var); }
std::istream& operator>>(std::istream& o, AutoConnectOption& var) { return int_to_type<AutoConnectOption> (o, var); }
std::istream& operator>>(std::istream& o, MonitorModel& var) { return int_to_type<MonitorModel> (o, var); }
+std::istream& operator>>(std::istream& o, RemoteModel& var) { return int_to_type<RemoteModel> (o, var); }
std::istream& operator>>(std::istream& o, EditMode& var) { return int_to_type<EditMode> (o, var); }
std::istream& operator>>(std::istream& o, SoloModel& var) { return int_to_type<SoloModel> (o, var); }
std::istream& operator>>(std::istream& o, LayerModel& var) { return int_to_type<LayerModel> (o, var); }
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index 4466c40a32..7c0deccca1 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cstdio>
@@ -52,6 +51,63 @@ using namespace PBD;
#define BLOCKSIZE 4096U
+class ImportableSource {
+ public:
+ ImportableSource (SNDFILE* sf, SF_INFO* info) : in (sf), sf_info (info) {}
+ virtual ~ImportableSource() {}
+
+ virtual nframes_t read (Sample* buffer, nframes_t nframes) {
+ nframes_t per_channel = nframes / sf_info->channels;
+ per_channel = sf_readf_float (in, buffer, per_channel);
+ return per_channel * sf_info->channels;
+ }
+
+ virtual float ratio() const { return 1.0f; }
+
+protected:
+ SNDFILE* in;
+ SF_INFO* sf_info;
+};
+
+class ResampledImportableSource : public ImportableSource {
+ public:
+ ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate) : ImportableSource (sf, info) {
+ int err;
+
+ sf_seek (in, 0, SEEK_SET) ;
+
+ /* Initialize the sample rate converter. */
+
+ if ((src_state = src_new (SRC_SINC_BEST_QUALITY, sf_info->channels, &err)) == 0) {
+ error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
+ throw failed_constructor ();
+ }
+
+ src_data.end_of_input = 0 ; /* Set this later. */
+
+ /* Start with zero to force load in while loop. */
+
+ src_data.input_frames = 0 ;
+ src_data.data_in = input ;
+
+ src_data.src_ratio = ((float) rate) / sf_info->samplerate ;
+
+ }
+
+ ~ResampledImportableSource () {
+ src_state = src_delete (src_state) ;
+ }
+
+ nframes_t read (Sample* buffer, nframes_t nframes);
+
+ float ratio() const { return src_data.src_ratio; }
+
+ private:
+ float input[BLOCKSIZE];
+ SRC_STATE* src_state;
+ SRC_DATA src_data;
+};
+
int
Session::import_audiofile (import_status& status)
{
@@ -62,7 +118,6 @@ Session::import_audiofile (import_status& status)
float *data = 0;
Sample **channel_data = 0;
long nfiles = 0;
- long n;
string basepath;
string sounds_dir;
nframes_t so_far;
@@ -70,42 +125,32 @@ Session::import_audiofile (import_status& status)
int ret = -1;
vector<string> new_paths;
struct tm* now;
- string tmp_convert_file;
-
+ ImportableSource* importable = 0;
+ const nframes_t nframes = BLOCKSIZE;
+
status.new_regions.clear ();
if ((in = sf_open (status.paths.front().c_str(), SFM_READ, &info)) == 0) {
error << string_compose(_("Import: cannot open input sound file \"%1\""), status.paths.front()) << endmsg;
+ status.done = 1;
+ status.cancel = 1;
return -1;
+ }
+
+ if ((nframes_t) info.samplerate != frame_rate()) {
+ importable = new ResampledImportableSource (in, &info, frame_rate());
} else {
- if ((uint32_t) info.samplerate != frame_rate()) {
- sf_close(in);
- status.doing_what = _("resampling audio");
- // resample to session frame_rate
- if (sample_rate_convert(status, status.paths.front(), tmp_convert_file)) {
- if ((in = sf_open (tmp_convert_file.c_str(), SFM_READ, &info)) == 0) {
- error << string_compose(_("Import: cannot open converted sound file \"%1\""), tmp_convert_file) << endmsg;
- return -1;
- }
- } else if (!status.cancel){
- // error
- error << string_compose(_("Import: error while resampling sound file \"%1\""), status.paths.front()) << endmsg;
- return -1;
- } else {
- // canceled
- goto out;
- }
- }
+ importable = new ImportableSource (in, &info);
}
- for (n = 0; n < info.channels; ++n) {
+ for (int n = 0; n < info.channels; ++n) {
newfiles.push_back (boost::shared_ptr<AudioFileSource>());
}
sounds_dir = discover_best_sound_dir ();
basepath = PBD::basename_nosuffix (status.paths.front());
- for (n = 0; n < info.channels; ++n) {
+ for (int n = 0; n < info.channels; ++n) {
bool goodfile = false;
@@ -117,12 +162,12 @@ Session::import_audiofile (import_status& status)
snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
}
} else if (info.channels > 1) {
- snprintf (buf, sizeof(buf), "%s/%s-c%lu.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
+ snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
} else {
snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
}
- if (::access (buf, F_OK) == 0) {
+ if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
/* if the file already exists, we must come up with
* a new name for it. for now we just keep appending
@@ -152,12 +197,11 @@ Session::import_audiofile (import_status& status)
nfiles++;
}
-
- data = new float[BLOCKSIZE * info.channels];
+ data = new float[nframes * info.channels];
channel_data = new Sample * [ info.channels ];
- for (n = 0; n < info.channels; ++n) {
- channel_data[n] = new Sample[BLOCKSIZE];
+ for (int n = 0; n < info.channels; ++n) {
+ channel_data[n] = new Sample[nframes];
}
so_far = 0;
@@ -167,18 +211,21 @@ Session::import_audiofile (import_status& status)
while (!status.cancel) {
- long nread;
+ nframes_t nread, nfread;
long x;
long chn;
-
- if ((nread = sf_readf_float (in, data, BLOCKSIZE)) == 0) {
+
+ if ((nread = importable->read (data, nframes)) == 0) {
break;
}
+ nfread = nread / info.channels;
/* de-interleave */
for (chn = 0; chn < info.channels; ++chn) {
- for (x = chn, n = 0; n < nread; x += info.channels, ++n) {
+
+ nframes_t n;
+ for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
channel_data[chn][n] = (Sample) data[x];
}
}
@@ -186,11 +233,15 @@ Session::import_audiofile (import_status& status)
/* flush to disk */
for (chn = 0; chn < info.channels; ++chn) {
- newfiles[chn]->write (channel_data[chn], nread);
+ newfiles[chn]->write (channel_data[chn], nfread);
}
so_far += nread;
- status.progress = so_far / (float) (info.frames * info.channels);
+ status.progress = so_far / (importable->ratio () * info.frames * info.channels);
+ }
+
+ if (status.cancel) {
+ goto out;
}
if (status.multichan) {
@@ -205,13 +256,10 @@ Session::import_audiofile (import_status& status)
time (&xnow);
now = localtime (&xnow);
- if (status.cancel) {
- goto out;
- }
-
if (status.multichan) {
/* all sources are used in a single multichannel region */
- for (n = 0; n < nfiles && !status.cancel; ++n) {
+
+ for (int n = 0; n < nfiles && !status.cancel; ++n) {
/* flush the final length to the header */
newfiles[n]->update_header(0, *now, xnow);
sources.push_back(newfiles[n]);
@@ -228,7 +276,7 @@ Session::import_audiofile (import_status& status)
status.new_regions.push_back (r);
} else {
- for (n = 0; n < nfiles && !status.cancel; ++n) {
+ for (int n = 0; n < nfiles && !status.cancel; ++n) {
/* flush the final length to the header */
@@ -263,7 +311,7 @@ Session::import_audiofile (import_status& status)
}
if (channel_data) {
- for (n = 0; n < info.channels; ++n) {
+ for (int n = 0; n < info.channels; ++n) {
delete [] channel_data[n];
}
delete [] channel_data;
@@ -277,116 +325,59 @@ Session::import_audiofile (import_status& status)
}
}
- if (tmp_convert_file.length()) {
- unlink(tmp_convert_file.c_str());
+ if (importable) {
+ delete importable;
}
-
- sf_close (in);
+
+ sf_close (in);
status.done = true;
+
return ret;
}
-string
-Session::build_tmp_convert_name(string infile)
+nframes_t
+ResampledImportableSource::read (Sample* output, nframes_t nframes)
{
- string tmp_name(_path + "/." + Glib::path_get_basename (infile.c_str()) + "XXXXXX");
- char* tmp = new char[tmp_name.length() + 1];
- tmp_name.copy(tmp, string::npos);
- tmp[tmp_name.length()] = 0;
- mkstemp(tmp);
- string outfile = tmp;
- delete [] tmp;
-
- return outfile;
-}
+ int err;
-bool
-Session::sample_rate_convert (import_status& status, string infile, string& outfile)
-{
- float input [BLOCKSIZE] ;
- float output [BLOCKSIZE] ;
-
- SF_INFO sf_info;
- SRC_STATE* src_state ;
- SRC_DATA src_data ;
- int err ;
- sf_count_t output_count = 0 ;
- sf_count_t input_count = 0;
-
- SNDFILE* in = sf_open(infile.c_str(), SFM_READ, &sf_info);
- if (!in) {
- error << string_compose(_("Import/SRC: could not open input file: %1"), outfile) << endmsg;
- return false;
- }
- sf_count_t total_input_frames = sf_info.frames;
+ /* If the input buffer is empty, refill it. */
- outfile = build_tmp_convert_name(infile);
- SNDFILE* out = sf_open(outfile.c_str(), SFM_RDWR, &sf_info);
- if (!out) {
- error << string_compose(_("Import/SRC: could not open output file: %1"), outfile) << endmsg;
- return false;
- }
-
- sf_seek (in, 0, SEEK_SET) ;
- sf_seek (out, 0, SEEK_SET) ;
-
- /* Initialize the sample rate converter. */
- if ((src_state = src_new (SRC_SINC_BEST_QUALITY, sf_info.channels, &err)) == 0) {
- error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
- return false ;
- }
+ if (src_data.input_frames == 0) {
- src_data.end_of_input = 0 ; /* Set this later. */
-
- /* Start with zero to force load in while loop. */
- src_data.input_frames = 0 ;
- src_data.data_in = input ;
-
- src_data.src_ratio = (1.0 * frame_rate()) / sf_info.samplerate ;
-
- src_data.data_out = output ;
- src_data.output_frames = BLOCKSIZE / sf_info.channels ;
-
- while (!status.cancel) {
- /* If the input buffer is empty, refill it. */
- if (src_data.input_frames == 0) {
- src_data.input_frames = sf_readf_float (in, input, BLOCKSIZE / sf_info.channels) ;
- src_data.data_in = input ;
-
- /* The last read will not be a full buffer, so snd_of_input. */
- if (src_data.input_frames < (int)BLOCKSIZE / sf_info.channels) {
- src_data.end_of_input = SF_TRUE ;
- }
- }
+ src_data.input_frames = ImportableSource::read (input, BLOCKSIZE);
- if ((err = src_process (src_state, &src_data))) {
- error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
- return false ;
- }
+ /* The last read will not be a full buffer, so set end_of_input. */
- /* Terminate if at end */
- if (src_data.end_of_input && src_data.output_frames_gen == 0) {
- break ;
- }
+ if ((nframes_t) src_data.input_frames < BLOCKSIZE) {
+ src_data.end_of_input = SF_TRUE ;
+ }
- /* Write output. */
- sf_writef_float (out, output, src_data.output_frames_gen) ;
- output_count += src_data.output_frames_gen ;
- input_count += src_data.input_frames_used;
+ src_data.input_frames /= sf_info->channels;
+ src_data.data_in = input ;
+ }
+
+ src_data.data_out = output;
- src_data.data_in += src_data.input_frames_used * sf_info.channels ;
- src_data.input_frames -= src_data.input_frames_used ;
-
- status.progress = (float) input_count / total_input_frames;
+ if (!src_data.end_of_input) {
+ src_data.output_frames = nframes / sf_info->channels ;
+ } else {
+ src_data.output_frames = src_data.input_frames;
}
- src_state = src_delete (src_state) ;
- sf_close(in);
- sf_close(out);
-
- if (status.cancel) {
- return false;
- } else {
- return true ;
+ if ((err = src_process (src_state, &src_data))) {
+ error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
+ return 0 ;
+ }
+
+ /* Terminate if at end */
+
+ if (src_data.end_of_input && src_data.output_frames_gen == 0) {
+ return 0;
}
+
+ src_data.data_in += src_data.input_frames_used * sf_info->channels ;
+ src_data.input_frames -= src_data.input_frames_used ;
+
+ return src_data.output_frames_gen * sf_info->channels;
}
+
diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc
index d109642fd4..e5d77c3951 100644
--- a/libs/ardour/insert.cc
+++ b/libs/ardour/insert.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <string>
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index b7472781a8..a9284d779c 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -27,6 +27,7 @@
#include <glibmm/thread.h>
#include <pbd/xml++.h>
+#include <pbd/replace_all.h>
#include <ardour/audioengine.h>
#include <ardour/io.h>
@@ -1817,6 +1818,12 @@ IO::set_name (string name, void* src)
return 0;
}
+ /* replace all colons in the name. i wish we didn't have to do this */
+
+ if (replace_all (name, ":", "-")) {
+ warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
+ }
+
for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
string current_name = i->short_name();
current_name.replace (current_name.find (_name), _name.length(), name);
diff --git a/libs/ardour/jack_slave.cc b/libs/ardour/jack_slave.cc
index 2e03b2f45d..a06e295a09 100644
--- a/libs/ardour/jack_slave.cc
+++ b/libs/ardour/jack_slave.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <iostream>
diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc
index c21d09e01b..ba944f3c08 100644
--- a/libs/ardour/ladspa_plugin.cc
+++ b/libs/ardour/ladspa_plugin.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS 1
diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc
index bec87e5dd6..3d04c66824 100644
--- a/libs/ardour/location.cc
+++ b/libs/ardour/location.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
@@ -662,7 +661,7 @@ struct LocationStartLaterComparison
};
Location *
-Locations::first_location_before (nframes_t frame)
+Locations::first_location_before (nframes_t frame, bool include_special_ranges)
{
LocationList locs;
@@ -677,6 +676,9 @@ Locations::first_location_before (nframes_t frame)
/* locs is now sorted latest..earliest */
for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
+ if (!include_special_ranges && ((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
+ continue;
+ }
if (!(*i)->is_hidden() && (*i)->start() < frame) {
return (*i);
}
@@ -686,7 +688,7 @@ Locations::first_location_before (nframes_t frame)
}
Location *
-Locations::first_location_after (nframes_t frame)
+Locations::first_location_after (nframes_t frame, bool include_special_ranges)
{
LocationList locs;
@@ -701,6 +703,9 @@ Locations::first_location_after (nframes_t frame)
/* locs is now sorted earliest..latest */
for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
+ if (!include_special_ranges && ((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
+ continue;
+ }
if (!(*i)->is_hidden() && (*i)->start() > frame) {
return (*i);
}
@@ -710,7 +715,7 @@ Locations::first_location_after (nframes_t frame)
}
nframes_t
-Locations::first_mark_before (nframes_t frame)
+Locations::first_mark_before (nframes_t frame, bool include_special_ranges)
{
LocationList locs;
@@ -725,6 +730,9 @@ Locations::first_mark_before (nframes_t frame)
/* locs is now sorted latest..earliest */
for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
+ if (!include_special_ranges && ((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
+ continue;
+ }
if (!(*i)->is_hidden()) {
if ((*i)->is_mark()) {
/* MARK: start == end */
@@ -747,7 +755,7 @@ Locations::first_mark_before (nframes_t frame)
}
nframes_t
-Locations::first_mark_after (nframes_t frame)
+Locations::first_mark_after (nframes_t frame, bool include_special_ranges)
{
LocationList locs;
@@ -762,6 +770,9 @@ Locations::first_mark_after (nframes_t frame)
/* locs is now sorted earliest..latest */
for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
+ if (!include_special_ranges && ((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
+ continue;
+ }
if (!(*i)->is_hidden()) {
if ((*i)->is_mark()) {
/* MARK, start == end so just compare start */
diff --git a/libs/ardour/macosx/English.lproj/InfoPlist.strings b/libs/ardour/macosx/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..0c0cacad8b
--- /dev/null
+++ b/libs/ardour/macosx/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/libs/ardour/macosx/Info.plist b/libs/ardour/macosx/Info.plist
new file mode 100644
index 0000000000..931491039f
--- /dev/null
+++ b/libs/ardour/macosx/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>ardour</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.carbonframeworktemplate</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.01</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/libs/ardour/macosx/ardour.xcodeproj/project.pbxproj b/libs/ardour/macosx/ardour.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..4026b65f59
--- /dev/null
+++ b/libs/ardour/macosx/ardour.xcodeproj/project.pbxproj
@@ -0,0 +1,1214 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 696149E90B97CEF500ECBDF0 /* glib in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149E50B97CEF500ECBDF0 /* glib */; };
+ 696149EA0B97CEF500ECBDF0 /* gmodule in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149E60B97CEF500ECBDF0 /* gmodule */; };
+ 696149EB0B97CEF500ECBDF0 /* gobject in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149E70B97CEF500ECBDF0 /* gobject */; };
+ 696149EC0B97CEF500ECBDF0 /* gthread in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149E80B97CEF500ECBDF0 /* gthread */; };
+ 6964FECA0B8E7A7900799BAE /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 6964FEC80B8E7A7900799BAE /* version.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6964FECB0B8E7A7900799BAE /* version.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6964FEC90B8E7A7900799BAE /* version.cc */; };
+ 696C90530B8D526000D66CAF /* ardour.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FAF0B8D526000D66CAF /* ardour.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90540B8D526000D66CAF /* audio_diskstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB00B8D526000D66CAF /* audio_diskstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90550B8D526000D66CAF /* audio_library.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB10B8D526000D66CAF /* audio_library.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90560B8D526000D66CAF /* audio_track.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB20B8D526000D66CAF /* audio_track.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90580B8D526000D66CAF /* audioengine.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB40B8D526000D66CAF /* audioengine.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90590B8D526000D66CAF /* audiofilesource.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB50B8D526000D66CAF /* audiofilesource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C905A0B8D526000D66CAF /* audiofilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB60B8D526000D66CAF /* audiofilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C905B0B8D526000D66CAF /* audioplaylist.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB70B8D526000D66CAF /* audioplaylist.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C905C0B8D526000D66CAF /* audioregion.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB80B8D526000D66CAF /* audioregion.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C905D0B8D526000D66CAF /* audiosource.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FB90B8D526000D66CAF /* audiosource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C905E0B8D526000D66CAF /* auditioner.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FBA0B8D526000D66CAF /* auditioner.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C905F0B8D526000D66CAF /* automation_event.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FBB0B8D526000D66CAF /* automation_event.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90600B8D526000D66CAF /* buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FBC0B8D526000D66CAF /* buffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90610B8D526000D66CAF /* click.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FBD0B8D526000D66CAF /* click.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90620B8D526000D66CAF /* configuration.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FBE0B8D526000D66CAF /* configuration.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90630B8D526000D66CAF /* configuration_variable.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FBF0B8D526000D66CAF /* configuration_variable.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90640B8D526000D66CAF /* configuration_vars.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC00B8D526000D66CAF /* configuration_vars.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90650B8D526000D66CAF /* connection.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC10B8D526000D66CAF /* connection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90660B8D526000D66CAF /* control_protocol_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC20B8D526000D66CAF /* control_protocol_manager.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90680B8D526000D66CAF /* crossfade.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC40B8D526000D66CAF /* crossfade.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90690B8D526000D66CAF /* crossfade_compare.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC50B8D526000D66CAF /* crossfade_compare.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C906A0B8D526000D66CAF /* curve.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC60B8D526000D66CAF /* curve.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C906B0B8D526000D66CAF /* cycle_timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC70B8D526000D66CAF /* cycle_timer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C906C0B8D526000D66CAF /* cycles.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC80B8D526000D66CAF /* cycles.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C906D0B8D526000D66CAF /* data_type.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FC90B8D526000D66CAF /* data_type.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C906E0B8D526000D66CAF /* dB.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FCA0B8D526000D66CAF /* dB.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90700B8D526000D66CAF /* diskstream.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FCC0B8D526000D66CAF /* diskstream.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90710B8D526000D66CAF /* export.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FCD0B8D526000D66CAF /* export.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90720B8D526000D66CAF /* gain.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FCE0B8D526000D66CAF /* gain.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90730B8D526000D66CAF /* gdither.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FCF0B8D526000D66CAF /* gdither.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90740B8D526000D66CAF /* gdither_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD00B8D526000D66CAF /* gdither_types.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90750B8D526000D66CAF /* gdither_types_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD10B8D526000D66CAF /* gdither_types_internal.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90760B8D526000D66CAF /* insert.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD20B8D526000D66CAF /* insert.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90770B8D526000D66CAF /* io.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD30B8D526000D66CAF /* io.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90780B8D526000D66CAF /* ladspa.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD40B8D526000D66CAF /* ladspa.h */; settings = {ATTRIBUTES = (); }; };
+ 696C90790B8D526000D66CAF /* ladspa_plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD50B8D526000D66CAF /* ladspa_plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C907A0B8D526000D66CAF /* location.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD60B8D526000D66CAF /* location.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C907B0B8D526000D66CAF /* logcurve.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD70B8D526000D66CAF /* logcurve.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C907C0B8D526000D66CAF /* mix.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD80B8D526000D66CAF /* mix.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C907D0B8D526000D66CAF /* named_selection.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FD90B8D526000D66CAF /* named_selection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C907E0B8D526000D66CAF /* noise.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FDA0B8D526000D66CAF /* noise.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C907F0B8D526000D66CAF /* osc.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FDB0B8D526000D66CAF /* osc.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90800B8D526000D66CAF /* panner.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FDC0B8D526000D66CAF /* panner.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90810B8D526000D66CAF /* pcm_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FDD0B8D526000D66CAF /* pcm_utils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90820B8D526000D66CAF /* peak.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FDE0B8D526000D66CAF /* peak.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90830B8D526000D66CAF /* playlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FDF0B8D526000D66CAF /* playlist.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90840B8D526000D66CAF /* playlist_factory.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE00B8D526000D66CAF /* playlist_factory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90850B8D526000D66CAF /* playlist_templates.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE10B8D526000D66CAF /* playlist_templates.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90860B8D526000D66CAF /* plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE20B8D526000D66CAF /* plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90870B8D526000D66CAF /* plugin_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE30B8D526000D66CAF /* plugin_manager.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90880B8D526000D66CAF /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE40B8D526000D66CAF /* port.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90890B8D526000D66CAF /* recent_sessions.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE50B8D526000D66CAF /* recent_sessions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C908A0B8D526000D66CAF /* redirect.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE60B8D526000D66CAF /* redirect.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C908B0B8D526000D66CAF /* region.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE70B8D526000D66CAF /* region.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C908C0B8D526000D66CAF /* region_factory.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE80B8D526000D66CAF /* region_factory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C908D0B8D526000D66CAF /* reverse.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FE90B8D526000D66CAF /* reverse.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C908E0B8D526000D66CAF /* route.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FEA0B8D526000D66CAF /* route.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C908F0B8D526000D66CAF /* route_group.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FEB0B8D526000D66CAF /* route_group.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90900B8D526000D66CAF /* route_group_specialized.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FEC0B8D526000D66CAF /* route_group_specialized.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90910B8D526000D66CAF /* send.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FED0B8D526000D66CAF /* send.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90920B8D526000D66CAF /* session.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FEE0B8D526000D66CAF /* session.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90930B8D526000D66CAF /* session_connection.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FEF0B8D526000D66CAF /* session_connection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90940B8D526000D66CAF /* session_playlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF00B8D526000D66CAF /* session_playlist.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90950B8D526000D66CAF /* session_region.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF10B8D526000D66CAF /* session_region.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90960B8D526000D66CAF /* session_route.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF20B8D526000D66CAF /* session_route.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90970B8D526000D66CAF /* session_selection.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF30B8D526000D66CAF /* session_selection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90980B8D526000D66CAF /* silentfilesource.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF40B8D526000D66CAF /* silentfilesource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90990B8D526000D66CAF /* slave.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF50B8D526000D66CAF /* slave.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C909A0B8D526000D66CAF /* sndfile_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF60B8D526000D66CAF /* sndfile_helpers.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C909B0B8D526000D66CAF /* sndfilesource.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF70B8D526000D66CAF /* sndfilesource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C909C0B8D526000D66CAF /* soundseq.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF80B8D526000D66CAF /* soundseq.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C909D0B8D526000D66CAF /* source.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FF90B8D526000D66CAF /* source.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C909E0B8D526000D66CAF /* source_factory.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FFA0B8D526000D66CAF /* source_factory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C909F0B8D526000D66CAF /* spline.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FFB0B8D526000D66CAF /* spline.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90A00B8D526000D66CAF /* tempo.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FFC0B8D526000D66CAF /* tempo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90A10B8D526000D66CAF /* timestamps.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FFD0B8D526000D66CAF /* timestamps.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90A20B8D526000D66CAF /* track.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FFE0B8D526000D66CAF /* track.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90A30B8D526000D66CAF /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C8FFF0B8D526000D66CAF /* types.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90A40B8D526000D66CAF /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C90000B8D526000D66CAF /* utils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 696C90A60B8D526000D66CAF /* audio_diskstream.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90020B8D526000D66CAF /* audio_diskstream.cc */; };
+ 696C90A70B8D526000D66CAF /* audio_library.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90030B8D526000D66CAF /* audio_library.cc */; };
+ 696C90A80B8D526000D66CAF /* audio_playlist.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90040B8D526000D66CAF /* audio_playlist.cc */; };
+ 696C90A90B8D526000D66CAF /* audio_track.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90050B8D526000D66CAF /* audio_track.cc */; };
+ 696C90AB0B8D526000D66CAF /* audioengine.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90070B8D526000D66CAF /* audioengine.cc */; };
+ 696C90AC0B8D526000D66CAF /* audiofilesource.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90080B8D526000D66CAF /* audiofilesource.cc */; };
+ 696C90AD0B8D526000D66CAF /* audiofilter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90090B8D526000D66CAF /* audiofilter.cc */; };
+ 696C90AE0B8D526000D66CAF /* audioregion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C900A0B8D526000D66CAF /* audioregion.cc */; };
+ 696C90AF0B8D526000D66CAF /* audiosource.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C900B0B8D526000D66CAF /* audiosource.cc */; };
+ 696C90B00B8D526000D66CAF /* auditioner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C900C0B8D526000D66CAF /* auditioner.cc */; };
+ 696C90B10B8D526000D66CAF /* automation.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C900D0B8D526000D66CAF /* automation.cc */; };
+ 696C90B20B8D526000D66CAF /* automation_event.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C900E0B8D526000D66CAF /* automation_event.cc */; };
+ 696C90B30B8D526000D66CAF /* configuration.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C900F0B8D526000D66CAF /* configuration.cc */; };
+ 696C90B40B8D526000D66CAF /* connection.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90100B8D526000D66CAF /* connection.cc */; };
+ 696C90B50B8D526000D66CAF /* control_protocol_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90110B8D526000D66CAF /* control_protocol_manager.cc */; };
+ 696C90B70B8D526000D66CAF /* crossfade.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90130B8D526000D66CAF /* crossfade.cc */; };
+ 696C90B80B8D526000D66CAF /* curve.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90140B8D526000D66CAF /* curve.cc */; };
+ 696C90B90B8D526000D66CAF /* cycle_timer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90150B8D526000D66CAF /* cycle_timer.cc */; };
+ 696C90BA0B8D526000D66CAF /* default_click.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90160B8D526000D66CAF /* default_click.cc */; };
+ 696C90BC0B8D526000D66CAF /* diskstream.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90180B8D526000D66CAF /* diskstream.cc */; };
+ 696C90BD0B8D526000D66CAF /* enums.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90190B8D526000D66CAF /* enums.cc */; };
+ 696C90BE0B8D526000D66CAF /* gain.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C901A0B8D526000D66CAF /* gain.cc */; };
+ 696C90BF0B8D526000D66CAF /* gdither.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C901B0B8D526000D66CAF /* gdither.cc */; };
+ 696C90C00B8D526000D66CAF /* gettext.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C901C0B8D526000D66CAF /* gettext.h */; settings = {ATTRIBUTES = (); }; };
+ 696C90C10B8D526000D66CAF /* globals.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C901D0B8D526000D66CAF /* globals.cc */; };
+ 696C90C20B8D526000D66CAF /* i18n.h in Headers */ = {isa = PBXBuildFile; fileRef = 696C901E0B8D526000D66CAF /* i18n.h */; settings = {ATTRIBUTES = (); }; };
+ 696C90C30B8D526000D66CAF /* import.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C901F0B8D526000D66CAF /* import.cc */; };
+ 696C90C40B8D526000D66CAF /* insert.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90200B8D526000D66CAF /* insert.cc */; };
+ 696C90C50B8D526000D66CAF /* io.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90210B8D526000D66CAF /* io.cc */; };
+ 696C90C60B8D526000D66CAF /* jack_slave.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90220B8D526000D66CAF /* jack_slave.cc */; };
+ 696C90C70B8D526000D66CAF /* ladspa_plugin.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90230B8D526000D66CAF /* ladspa_plugin.cc */; };
+ 696C90C80B8D526000D66CAF /* location.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90240B8D526000D66CAF /* location.cc */; };
+ 696C90C90B8D526000D66CAF /* mix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90250B8D526000D66CAF /* mix.cc */; };
+ 696C90CA0B8D526000D66CAF /* mtc_slave.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90260B8D526000D66CAF /* mtc_slave.cc */; };
+ 696C90CB0B8D526000D66CAF /* named_selection.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90270B8D526000D66CAF /* named_selection.cc */; };
+ 696C90CC0B8D526000D66CAF /* osc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90280B8D526000D66CAF /* osc.cc */; };
+ 696C90CD0B8D526000D66CAF /* panner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90290B8D526000D66CAF /* panner.cc */; };
+ 696C90CE0B8D526000D66CAF /* pcm_utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C902A0B8D526000D66CAF /* pcm_utils.cc */; };
+ 696C90CF0B8D526000D66CAF /* playlist.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C902B0B8D526000D66CAF /* playlist.cc */; };
+ 696C90D00B8D526000D66CAF /* playlist_factory.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C902C0B8D526000D66CAF /* playlist_factory.cc */; };
+ 696C90D10B8D526000D66CAF /* plugin.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C902D0B8D526000D66CAF /* plugin.cc */; };
+ 696C90D20B8D526000D66CAF /* plugin_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C902E0B8D526000D66CAF /* plugin_manager.cc */; };
+ 696C90D30B8D526000D66CAF /* port.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C902F0B8D526000D66CAF /* port.cc */; };
+ 696C90D40B8D526000D66CAF /* recent_sessions.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90300B8D526000D66CAF /* recent_sessions.cc */; };
+ 696C90D50B8D526000D66CAF /* redirect.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90310B8D526000D66CAF /* redirect.cc */; };
+ 696C90D60B8D526000D66CAF /* region.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90320B8D526000D66CAF /* region.cc */; };
+ 696C90D70B8D526000D66CAF /* region_factory.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90330B8D526000D66CAF /* region_factory.cc */; };
+ 696C90D80B8D526000D66CAF /* reverse.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90340B8D526000D66CAF /* reverse.cc */; };
+ 696C90D90B8D526000D66CAF /* route.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90350B8D526000D66CAF /* route.cc */; };
+ 696C90DA0B8D526000D66CAF /* route_group.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90360B8D526000D66CAF /* route_group.cc */; };
+ 696C90DB0B8D526000D66CAF /* send.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90370B8D526000D66CAF /* send.cc */; };
+ 696C90DC0B8D526000D66CAF /* session.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90380B8D526000D66CAF /* session.cc */; };
+ 696C90DD0B8D526000D66CAF /* session_butler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90390B8D526000D66CAF /* session_butler.cc */; };
+ 696C90DE0B8D526000D66CAF /* session_click.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C903A0B8D526000D66CAF /* session_click.cc */; };
+ 696C90DF0B8D526000D66CAF /* session_command.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C903B0B8D526000D66CAF /* session_command.cc */; };
+ 696C90E10B8D526000D66CAF /* session_events.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C903D0B8D526000D66CAF /* session_events.cc */; };
+ 696C90E20B8D526000D66CAF /* session_export.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C903E0B8D526000D66CAF /* session_export.cc */; };
+ 696C90E30B8D526000D66CAF /* session_feedback.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C903F0B8D526000D66CAF /* session_feedback.cc */; };
+ 696C90E40B8D526000D66CAF /* session_midi.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90400B8D526000D66CAF /* session_midi.cc */; };
+ 696C90E50B8D526000D66CAF /* session_process.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90410B8D526000D66CAF /* session_process.cc */; };
+ 696C90E60B8D526000D66CAF /* session_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90420B8D526000D66CAF /* session_state.cc */; };
+ 696C90E70B8D526000D66CAF /* session_time.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90430B8D526000D66CAF /* session_time.cc */; };
+ 696C90E80B8D526000D66CAF /* session_timefx.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90440B8D526000D66CAF /* session_timefx.cc */; };
+ 696C90E90B8D526000D66CAF /* session_transport.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90450B8D526000D66CAF /* session_transport.cc */; };
+ 696C90EB0B8D526000D66CAF /* silentfilesource.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90470B8D526000D66CAF /* silentfilesource.cc */; };
+ 696C90EC0B8D526000D66CAF /* sndfile_helpers.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90480B8D526000D66CAF /* sndfile_helpers.cc */; };
+ 696C90ED0B8D526000D66CAF /* sndfilesource.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90490B8D526000D66CAF /* sndfilesource.cc */; };
+ 696C90EE0B8D526000D66CAF /* source.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C904A0B8D526000D66CAF /* source.cc */; };
+ 696C90EF0B8D526000D66CAF /* source_factory.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C904B0B8D526000D66CAF /* source_factory.cc */; };
+ 696C90F20B8D526000D66CAF /* tempo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C904E0B8D526000D66CAF /* tempo.cc */; };
+ 696C90F30B8D526000D66CAF /* track.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C904F0B8D526000D66CAF /* track.cc */; };
+ 696C90F40B8D526000D66CAF /* utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 696C90500B8D526000D66CAF /* utils.cc */; };
+ 696C91000B8D52F300D66CAF /* glibmm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90F70B8D52F300D66CAF /* glibmm.framework */; };
+ 696C91010B8D52F300D66CAF /* Jack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90F80B8D52F300D66CAF /* Jack.framework */; };
+ 696C91020B8D52F300D66CAF /* lo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90F90B8D52F300D66CAF /* lo.framework */; };
+ 696C91030B8D52F300D66CAF /* LRdf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90FA0B8D52F300D66CAF /* LRdf.framework */; };
+ 696C91040B8D52F300D66CAF /* Raptor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90FB0B8D52F300D66CAF /* Raptor.framework */; };
+ 696C91050B8D52F300D66CAF /* SampleRate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90FC0B8D52F300D66CAF /* SampleRate.framework */; };
+ 696C91060B8D52F300D66CAF /* sigc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90FD0B8D52F300D66CAF /* sigc.framework */; };
+ 696C91070B8D52F300D66CAF /* Sndfile-ardour.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90FE0B8D52F300D66CAF /* Sndfile-ardour.framework */; };
+ 696C91080B8D52F300D66CAF /* soundtouch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 696C90FF0B8D52F300D66CAF /* soundtouch.framework */; };
+ 697D98090B8DCD8C0006A892 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 697D98080B8DCD8C0006A892 /* libxml2.dylib */; };
+ 698D9AB60B969A6F00C53B63 /* midi++.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 698D9AB50B969A5B00C53B63 /* midi++.framework */; };
+ 69AD45850B97D10600806E7E /* FLAC in Frameworks */ = {isa = PBXBuildFile; fileRef = 69AD45840B97D10600806E7E /* FLAC */; };
+ 69B1B5210B8E7DFD007E41C1 /* pbd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 691B3B7C0B8D5508009155B5 /* pbd.framework */; };
+ 69B1B5500B8E80AD007E41C1 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69B1B54F0B8E80AD007E41C1 /* CoreAudio.framework */; };
+ 69DBC41B0BA794A500C19E65 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DBC41A0BA794A500C19E65 /* Accelerate.framework */; };
+ 69DBC42B0BA7992800C19E65 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69DBC42A0BA7992800C19E65 /* Carbon.framework */; };
+ 69F7CE5A0B8DCB3300D76871 /* basic_ui.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69F7CE520B8DCB3300D76871 /* basic_ui.cc */; };
+ 69F7CE5B0B8DCB3300D76871 /* basic_ui.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F7CE540B8DCB3300D76871 /* basic_ui.h */; };
+ 69F7CE5C0B8DCB3300D76871 /* control_protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F7CE550B8DCB3300D76871 /* control_protocol.h */; };
+ 69F7CE5D0B8DCB3300D76871 /* smpte.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F7CE560B8DCB3300D76871 /* smpte.h */; };
+ 69F7CE5E0B8DCB3300D76871 /* control_protocol.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69F7CE570B8DCB3300D76871 /* control_protocol.cc */; };
+ 69F7CE600B8DCB3300D76871 /* smpte.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69F7CE590B8DCB3300D76871 /* smpte.cc */; };
+ 8D07F2BE0486CC7A007CD1D0 /* ardour_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32BAE0B70371A74B00C91783 /* ardour_Prefix.pch */; settings = {ATTRIBUTES = (); }; };
+ 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 691B3B7B0B8D5508009155B5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 691B3B770B8D5508009155B5 /* pbd.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 8D07F2C80486CC7A007CD1D0;
+ remoteInfo = pbd;
+ };
+ 698D9AB40B969A5B00C53B63 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 698D9AB00B969A5B00C53B63 /* midi++.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 8D07F2C80486CC7A007CD1D0;
+ remoteInfo = "midi++";
+ };
+ 698D9AB90B969ADC00C53B63 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 698D9AB00B969A5B00C53B63 /* midi++.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = "midi++";
+ };
+ 69D5F6250B8D58A500301E71 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 691B3B770B8D5508009155B5 /* pbd.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = pbd;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 32BAE0B70371A74B00C91783 /* ardour_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ardour_Prefix.pch; sourceTree = "<group>"; };
+ 691B3B770B8D5508009155B5 /* pbd.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = pbd.xcodeproj; path = ../../pbd/macosx/pbd.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 696149E50B97CEF500ECBDF0 /* glib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = glib; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/glib; sourceTree = "<absolute>"; };
+ 696149E60B97CEF500ECBDF0 /* gmodule */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gmodule; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gmodule; sourceTree = "<absolute>"; };
+ 696149E70B97CEF500ECBDF0 /* gobject */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gobject; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gobject; sourceTree = "<absolute>"; };
+ 696149E80B97CEF500ECBDF0 /* gthread */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gthread; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gthread; sourceTree = "<absolute>"; };
+ 6964FEC80B8E7A7900799BAE /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
+ 6964FEC90B8E7A7900799BAE /* version.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = version.cc; sourceTree = "<group>"; };
+ 696C8FAF0B8D526000D66CAF /* ardour.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ardour.h; sourceTree = "<group>"; };
+ 696C8FB00B8D526000D66CAF /* audio_diskstream.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audio_diskstream.h; sourceTree = "<group>"; };
+ 696C8FB10B8D526000D66CAF /* audio_library.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audio_library.h; sourceTree = "<group>"; };
+ 696C8FB20B8D526000D66CAF /* audio_track.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audio_track.h; sourceTree = "<group>"; };
+ 696C8FB40B8D526000D66CAF /* audioengine.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audioengine.h; sourceTree = "<group>"; };
+ 696C8FB50B8D526000D66CAF /* audiofilesource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audiofilesource.h; sourceTree = "<group>"; };
+ 696C8FB60B8D526000D66CAF /* audiofilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audiofilter.h; sourceTree = "<group>"; };
+ 696C8FB70B8D526000D66CAF /* audioplaylist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audioplaylist.h; sourceTree = "<group>"; };
+ 696C8FB80B8D526000D66CAF /* audioregion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audioregion.h; sourceTree = "<group>"; };
+ 696C8FB90B8D526000D66CAF /* audiosource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = audiosource.h; sourceTree = "<group>"; };
+ 696C8FBA0B8D526000D66CAF /* auditioner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = auditioner.h; sourceTree = "<group>"; };
+ 696C8FBB0B8D526000D66CAF /* automation_event.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = automation_event.h; sourceTree = "<group>"; };
+ 696C8FBC0B8D526000D66CAF /* buffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = buffer.h; sourceTree = "<group>"; };
+ 696C8FBD0B8D526000D66CAF /* click.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = click.h; sourceTree = "<group>"; };
+ 696C8FBE0B8D526000D66CAF /* configuration.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = configuration.h; sourceTree = "<group>"; };
+ 696C8FBF0B8D526000D66CAF /* configuration_variable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = configuration_variable.h; sourceTree = "<group>"; };
+ 696C8FC00B8D526000D66CAF /* configuration_vars.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = configuration_vars.h; sourceTree = "<group>"; };
+ 696C8FC10B8D526000D66CAF /* connection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = connection.h; sourceTree = "<group>"; };
+ 696C8FC20B8D526000D66CAF /* control_protocol_manager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = control_protocol_manager.h; sourceTree = "<group>"; };
+ 696C8FC40B8D526000D66CAF /* crossfade.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crossfade.h; sourceTree = "<group>"; };
+ 696C8FC50B8D526000D66CAF /* crossfade_compare.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crossfade_compare.h; sourceTree = "<group>"; };
+ 696C8FC60B8D526000D66CAF /* curve.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = curve.h; sourceTree = "<group>"; };
+ 696C8FC70B8D526000D66CAF /* cycle_timer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cycle_timer.h; sourceTree = "<group>"; };
+ 696C8FC80B8D526000D66CAF /* cycles.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cycles.h; sourceTree = "<group>"; };
+ 696C8FC90B8D526000D66CAF /* data_type.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = data_type.h; sourceTree = "<group>"; };
+ 696C8FCA0B8D526000D66CAF /* dB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dB.h; sourceTree = "<group>"; };
+ 696C8FCC0B8D526000D66CAF /* diskstream.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = diskstream.h; sourceTree = "<group>"; };
+ 696C8FCD0B8D526000D66CAF /* export.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = export.h; sourceTree = "<group>"; };
+ 696C8FCE0B8D526000D66CAF /* gain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gain.h; sourceTree = "<group>"; };
+ 696C8FCF0B8D526000D66CAF /* gdither.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gdither.h; sourceTree = "<group>"; };
+ 696C8FD00B8D526000D66CAF /* gdither_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gdither_types.h; sourceTree = "<group>"; };
+ 696C8FD10B8D526000D66CAF /* gdither_types_internal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gdither_types_internal.h; sourceTree = "<group>"; };
+ 696C8FD20B8D526000D66CAF /* insert.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = insert.h; sourceTree = "<group>"; };
+ 696C8FD30B8D526000D66CAF /* io.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = io.h; sourceTree = "<group>"; };
+ 696C8FD40B8D526000D66CAF /* ladspa.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ladspa.h; sourceTree = "<group>"; };
+ 696C8FD50B8D526000D66CAF /* ladspa_plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ladspa_plugin.h; sourceTree = "<group>"; };
+ 696C8FD60B8D526000D66CAF /* location.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = location.h; sourceTree = "<group>"; };
+ 696C8FD70B8D526000D66CAF /* logcurve.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = logcurve.h; sourceTree = "<group>"; };
+ 696C8FD80B8D526000D66CAF /* mix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mix.h; sourceTree = "<group>"; };
+ 696C8FD90B8D526000D66CAF /* named_selection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = named_selection.h; sourceTree = "<group>"; };
+ 696C8FDA0B8D526000D66CAF /* noise.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = noise.h; sourceTree = "<group>"; };
+ 696C8FDB0B8D526000D66CAF /* osc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = osc.h; sourceTree = "<group>"; };
+ 696C8FDC0B8D526000D66CAF /* panner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = panner.h; sourceTree = "<group>"; };
+ 696C8FDD0B8D526000D66CAF /* pcm_utils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pcm_utils.h; sourceTree = "<group>"; };
+ 696C8FDE0B8D526000D66CAF /* peak.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = peak.h; sourceTree = "<group>"; };
+ 696C8FDF0B8D526000D66CAF /* playlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = playlist.h; sourceTree = "<group>"; };
+ 696C8FE00B8D526000D66CAF /* playlist_factory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = playlist_factory.h; sourceTree = "<group>"; };
+ 696C8FE10B8D526000D66CAF /* playlist_templates.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = playlist_templates.h; sourceTree = "<group>"; };
+ 696C8FE20B8D526000D66CAF /* plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = plugin.h; sourceTree = "<group>"; };
+ 696C8FE30B8D526000D66CAF /* plugin_manager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = plugin_manager.h; sourceTree = "<group>"; };
+ 696C8FE40B8D526000D66CAF /* port.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = port.h; sourceTree = "<group>"; };
+ 696C8FE50B8D526000D66CAF /* recent_sessions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = recent_sessions.h; sourceTree = "<group>"; };
+ 696C8FE60B8D526000D66CAF /* redirect.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = redirect.h; sourceTree = "<group>"; };
+ 696C8FE70B8D526000D66CAF /* region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = region.h; sourceTree = "<group>"; };
+ 696C8FE80B8D526000D66CAF /* region_factory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = region_factory.h; sourceTree = "<group>"; };
+ 696C8FE90B8D526000D66CAF /* reverse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reverse.h; sourceTree = "<group>"; };
+ 696C8FEA0B8D526000D66CAF /* route.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = route.h; sourceTree = "<group>"; };
+ 696C8FEB0B8D526000D66CAF /* route_group.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = route_group.h; sourceTree = "<group>"; };
+ 696C8FEC0B8D526000D66CAF /* route_group_specialized.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = route_group_specialized.h; sourceTree = "<group>"; };
+ 696C8FED0B8D526000D66CAF /* send.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = send.h; sourceTree = "<group>"; };
+ 696C8FEE0B8D526000D66CAF /* session.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = "<group>"; };
+ 696C8FEF0B8D526000D66CAF /* session_connection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session_connection.h; sourceTree = "<group>"; };
+ 696C8FF00B8D526000D66CAF /* session_playlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session_playlist.h; sourceTree = "<group>"; };
+ 696C8FF10B8D526000D66CAF /* session_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session_region.h; sourceTree = "<group>"; };
+ 696C8FF20B8D526000D66CAF /* session_route.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session_route.h; sourceTree = "<group>"; };
+ 696C8FF30B8D526000D66CAF /* session_selection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = session_selection.h; sourceTree = "<group>"; };
+ 696C8FF40B8D526000D66CAF /* silentfilesource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = silentfilesource.h; sourceTree = "<group>"; };
+ 696C8FF50B8D526000D66CAF /* slave.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = slave.h; sourceTree = "<group>"; };
+ 696C8FF60B8D526000D66CAF /* sndfile_helpers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sndfile_helpers.h; sourceTree = "<group>"; };
+ 696C8FF70B8D526000D66CAF /* sndfilesource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sndfilesource.h; sourceTree = "<group>"; };
+ 696C8FF80B8D526000D66CAF /* soundseq.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = soundseq.h; sourceTree = "<group>"; };
+ 696C8FF90B8D526000D66CAF /* source.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source.h; sourceTree = "<group>"; };
+ 696C8FFA0B8D526000D66CAF /* source_factory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_factory.h; sourceTree = "<group>"; };
+ 696C8FFB0B8D526000D66CAF /* spline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = spline.h; sourceTree = "<group>"; };
+ 696C8FFC0B8D526000D66CAF /* tempo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tempo.h; sourceTree = "<group>"; };
+ 696C8FFD0B8D526000D66CAF /* timestamps.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = timestamps.h; sourceTree = "<group>"; };
+ 696C8FFE0B8D526000D66CAF /* track.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = track.h; sourceTree = "<group>"; };
+ 696C8FFF0B8D526000D66CAF /* types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = "<group>"; };
+ 696C90000B8D526000D66CAF /* utils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
+ 696C90020B8D526000D66CAF /* audio_diskstream.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audio_diskstream.cc; path = ../audio_diskstream.cc; sourceTree = SOURCE_ROOT; };
+ 696C90030B8D526000D66CAF /* audio_library.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audio_library.cc; path = ../audio_library.cc; sourceTree = SOURCE_ROOT; };
+ 696C90040B8D526000D66CAF /* audio_playlist.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audio_playlist.cc; path = ../audio_playlist.cc; sourceTree = SOURCE_ROOT; };
+ 696C90050B8D526000D66CAF /* audio_track.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audio_track.cc; path = ../audio_track.cc; sourceTree = SOURCE_ROOT; };
+ 696C90070B8D526000D66CAF /* audioengine.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audioengine.cc; path = ../audioengine.cc; sourceTree = SOURCE_ROOT; };
+ 696C90080B8D526000D66CAF /* audiofilesource.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audiofilesource.cc; path = ../audiofilesource.cc; sourceTree = SOURCE_ROOT; };
+ 696C90090B8D526000D66CAF /* audiofilter.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audiofilter.cc; path = ../audiofilter.cc; sourceTree = SOURCE_ROOT; };
+ 696C900A0B8D526000D66CAF /* audioregion.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audioregion.cc; path = ../audioregion.cc; sourceTree = SOURCE_ROOT; };
+ 696C900B0B8D526000D66CAF /* audiosource.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = audiosource.cc; path = ../audiosource.cc; sourceTree = SOURCE_ROOT; };
+ 696C900C0B8D526000D66CAF /* auditioner.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = auditioner.cc; path = ../auditioner.cc; sourceTree = SOURCE_ROOT; };
+ 696C900D0B8D526000D66CAF /* automation.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = automation.cc; path = ../automation.cc; sourceTree = SOURCE_ROOT; };
+ 696C900E0B8D526000D66CAF /* automation_event.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = automation_event.cc; path = ../automation_event.cc; sourceTree = SOURCE_ROOT; };
+ 696C900F0B8D526000D66CAF /* configuration.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = configuration.cc; path = ../configuration.cc; sourceTree = SOURCE_ROOT; };
+ 696C90100B8D526000D66CAF /* connection.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = connection.cc; path = ../connection.cc; sourceTree = SOURCE_ROOT; };
+ 696C90110B8D526000D66CAF /* control_protocol_manager.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = control_protocol_manager.cc; path = ../control_protocol_manager.cc; sourceTree = SOURCE_ROOT; };
+ 696C90130B8D526000D66CAF /* crossfade.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = crossfade.cc; path = ../crossfade.cc; sourceTree = SOURCE_ROOT; };
+ 696C90140B8D526000D66CAF /* curve.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = curve.cc; path = ../curve.cc; sourceTree = SOURCE_ROOT; };
+ 696C90150B8D526000D66CAF /* cycle_timer.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = cycle_timer.cc; path = ../cycle_timer.cc; sourceTree = SOURCE_ROOT; };
+ 696C90160B8D526000D66CAF /* default_click.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = default_click.cc; path = ../default_click.cc; sourceTree = SOURCE_ROOT; };
+ 696C90180B8D526000D66CAF /* diskstream.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = diskstream.cc; path = ../diskstream.cc; sourceTree = SOURCE_ROOT; };
+ 696C90190B8D526000D66CAF /* enums.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = enums.cc; path = ../enums.cc; sourceTree = SOURCE_ROOT; };
+ 696C901A0B8D526000D66CAF /* gain.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = gain.cc; path = ../gain.cc; sourceTree = SOURCE_ROOT; };
+ 696C901B0B8D526000D66CAF /* gdither.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = gdither.cc; path = ../gdither.cc; sourceTree = SOURCE_ROOT; };
+ 696C901C0B8D526000D66CAF /* gettext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = gettext.h; path = ../gettext.h; sourceTree = SOURCE_ROOT; };
+ 696C901D0B8D526000D66CAF /* globals.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = globals.cc; path = ../globals.cc; sourceTree = SOURCE_ROOT; };
+ 696C901E0B8D526000D66CAF /* i18n.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = i18n.h; path = ../i18n.h; sourceTree = SOURCE_ROOT; };
+ 696C901F0B8D526000D66CAF /* import.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = import.cc; path = ../import.cc; sourceTree = SOURCE_ROOT; };
+ 696C90200B8D526000D66CAF /* insert.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = insert.cc; path = ../insert.cc; sourceTree = SOURCE_ROOT; };
+ 696C90210B8D526000D66CAF /* io.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = io.cc; path = ../io.cc; sourceTree = SOURCE_ROOT; };
+ 696C90220B8D526000D66CAF /* jack_slave.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = jack_slave.cc; path = ../jack_slave.cc; sourceTree = SOURCE_ROOT; };
+ 696C90230B8D526000D66CAF /* ladspa_plugin.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ladspa_plugin.cc; path = ../ladspa_plugin.cc; sourceTree = SOURCE_ROOT; };
+ 696C90240B8D526000D66CAF /* location.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = location.cc; path = ../location.cc; sourceTree = SOURCE_ROOT; };
+ 696C90250B8D526000D66CAF /* mix.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mix.cc; path = ../mix.cc; sourceTree = SOURCE_ROOT; };
+ 696C90260B8D526000D66CAF /* mtc_slave.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mtc_slave.cc; path = ../mtc_slave.cc; sourceTree = SOURCE_ROOT; };
+ 696C90270B8D526000D66CAF /* named_selection.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = named_selection.cc; path = ../named_selection.cc; sourceTree = SOURCE_ROOT; };
+ 696C90280B8D526000D66CAF /* osc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = osc.cc; path = ../osc.cc; sourceTree = SOURCE_ROOT; };
+ 696C90290B8D526000D66CAF /* panner.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = panner.cc; path = ../panner.cc; sourceTree = SOURCE_ROOT; };
+ 696C902A0B8D526000D66CAF /* pcm_utils.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pcm_utils.cc; path = ../pcm_utils.cc; sourceTree = SOURCE_ROOT; };
+ 696C902B0B8D526000D66CAF /* playlist.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = playlist.cc; path = ../playlist.cc; sourceTree = SOURCE_ROOT; };
+ 696C902C0B8D526000D66CAF /* playlist_factory.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = playlist_factory.cc; path = ../playlist_factory.cc; sourceTree = SOURCE_ROOT; };
+ 696C902D0B8D526000D66CAF /* plugin.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = plugin.cc; path = ../plugin.cc; sourceTree = SOURCE_ROOT; };
+ 696C902E0B8D526000D66CAF /* plugin_manager.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = plugin_manager.cc; path = ../plugin_manager.cc; sourceTree = SOURCE_ROOT; };
+ 696C902F0B8D526000D66CAF /* port.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = port.cc; path = ../port.cc; sourceTree = SOURCE_ROOT; };
+ 696C90300B8D526000D66CAF /* recent_sessions.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = recent_sessions.cc; path = ../recent_sessions.cc; sourceTree = SOURCE_ROOT; };
+ 696C90310B8D526000D66CAF /* redirect.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = redirect.cc; path = ../redirect.cc; sourceTree = SOURCE_ROOT; };
+ 696C90320B8D526000D66CAF /* region.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = region.cc; path = ../region.cc; sourceTree = SOURCE_ROOT; };
+ 696C90330B8D526000D66CAF /* region_factory.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = region_factory.cc; path = ../region_factory.cc; sourceTree = SOURCE_ROOT; };
+ 696C90340B8D526000D66CAF /* reverse.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = reverse.cc; path = ../reverse.cc; sourceTree = SOURCE_ROOT; };
+ 696C90350B8D526000D66CAF /* route.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = route.cc; path = ../route.cc; sourceTree = SOURCE_ROOT; };
+ 696C90360B8D526000D66CAF /* route_group.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = route_group.cc; path = ../route_group.cc; sourceTree = SOURCE_ROOT; };
+ 696C90370B8D526000D66CAF /* send.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = send.cc; path = ../send.cc; sourceTree = SOURCE_ROOT; };
+ 696C90380B8D526000D66CAF /* session.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session.cc; path = ../session.cc; sourceTree = SOURCE_ROOT; };
+ 696C90390B8D526000D66CAF /* session_butler.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_butler.cc; path = ../session_butler.cc; sourceTree = SOURCE_ROOT; };
+ 696C903A0B8D526000D66CAF /* session_click.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_click.cc; path = ../session_click.cc; sourceTree = SOURCE_ROOT; };
+ 696C903B0B8D526000D66CAF /* session_command.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_command.cc; path = ../session_command.cc; sourceTree = SOURCE_ROOT; };
+ 696C903D0B8D526000D66CAF /* session_events.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_events.cc; path = ../session_events.cc; sourceTree = SOURCE_ROOT; };
+ 696C903E0B8D526000D66CAF /* session_export.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_export.cc; path = ../session_export.cc; sourceTree = SOURCE_ROOT; };
+ 696C903F0B8D526000D66CAF /* session_feedback.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_feedback.cc; path = ../session_feedback.cc; sourceTree = SOURCE_ROOT; };
+ 696C90400B8D526000D66CAF /* session_midi.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_midi.cc; path = ../session_midi.cc; sourceTree = SOURCE_ROOT; };
+ 696C90410B8D526000D66CAF /* session_process.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_process.cc; path = ../session_process.cc; sourceTree = SOURCE_ROOT; };
+ 696C90420B8D526000D66CAF /* session_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_state.cc; path = ../session_state.cc; sourceTree = SOURCE_ROOT; };
+ 696C90430B8D526000D66CAF /* session_time.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_time.cc; path = ../session_time.cc; sourceTree = SOURCE_ROOT; };
+ 696C90440B8D526000D66CAF /* session_timefx.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_timefx.cc; path = ../session_timefx.cc; sourceTree = SOURCE_ROOT; };
+ 696C90450B8D526000D66CAF /* session_transport.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = session_transport.cc; path = ../session_transport.cc; sourceTree = SOURCE_ROOT; };
+ 696C90470B8D526000D66CAF /* silentfilesource.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = silentfilesource.cc; path = ../silentfilesource.cc; sourceTree = SOURCE_ROOT; };
+ 696C90480B8D526000D66CAF /* sndfile_helpers.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = sndfile_helpers.cc; path = ../sndfile_helpers.cc; sourceTree = SOURCE_ROOT; };
+ 696C90490B8D526000D66CAF /* sndfilesource.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = sndfilesource.cc; path = ../sndfilesource.cc; sourceTree = SOURCE_ROOT; };
+ 696C904A0B8D526000D66CAF /* source.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = source.cc; path = ../source.cc; sourceTree = SOURCE_ROOT; };
+ 696C904B0B8D526000D66CAF /* source_factory.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = source_factory.cc; path = ../source_factory.cc; sourceTree = SOURCE_ROOT; };
+ 696C904E0B8D526000D66CAF /* tempo.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = tempo.cc; path = ../tempo.cc; sourceTree = SOURCE_ROOT; };
+ 696C904F0B8D526000D66CAF /* track.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = track.cc; path = ../track.cc; sourceTree = SOURCE_ROOT; };
+ 696C90500B8D526000D66CAF /* utils.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = utils.cc; path = ../utils.cc; sourceTree = SOURCE_ROOT; };
+ 696C90F70B8D52F300D66CAF /* glibmm.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = glibmm.framework; path = /Library/Frameworks/glibmm.framework; sourceTree = "<absolute>"; };
+ 696C90F80B8D52F300D66CAF /* Jack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Jack.framework; path = /Library/Frameworks/Jack.framework; sourceTree = "<absolute>"; };
+ 696C90F90B8D52F300D66CAF /* lo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = lo.framework; path = /Library/Frameworks/lo.framework; sourceTree = "<absolute>"; };
+ 696C90FA0B8D52F300D66CAF /* LRdf.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LRdf.framework; path = /Library/Frameworks/LRdf.framework; sourceTree = "<absolute>"; };
+ 696C90FB0B8D52F300D66CAF /* Raptor.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Raptor.framework; path = /Library/Frameworks/Raptor.framework; sourceTree = "<absolute>"; };
+ 696C90FC0B8D52F300D66CAF /* SampleRate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SampleRate.framework; path = /Library/Frameworks/SampleRate.framework; sourceTree = "<absolute>"; };
+ 696C90FD0B8D52F300D66CAF /* sigc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = sigc.framework; path = /Library/Frameworks/sigc.framework; sourceTree = "<absolute>"; };
+ 696C90FE0B8D52F300D66CAF /* Sndfile-ardour.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "Sndfile-ardour.framework"; path = "/Library/Frameworks/Sndfile-ardour.framework"; sourceTree = "<absolute>"; };
+ 696C90FF0B8D52F300D66CAF /* soundtouch.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = soundtouch.framework; path = /Library/Frameworks/soundtouch.framework; sourceTree = "<absolute>"; };
+ 697D98080B8DCD8C0006A892 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = /usr/lib/libxml2.dylib; sourceTree = "<absolute>"; };
+ 698D9AB00B969A5B00C53B63 /* midi++.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "midi++.xcodeproj"; path = "../../midi++2/macosx/midi++.xcodeproj"; sourceTree = SOURCE_ROOT; };
+ 69AD45840B97D10600806E7E /* FLAC */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = FLAC; path = "/Library/Frameworks/Sndfile-ardour.framework/Versions/A/Libraries/FLAC"; sourceTree = "<absolute>"; };
+ 69B1B54F0B8E80AD007E41C1 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
+ 69DBC41A0BA794A500C19E65 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = "<absolute>"; };
+ 69DBC42A0BA7992800C19E65 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+ 69F7CE520B8DCB3300D76871 /* basic_ui.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = basic_ui.cc; sourceTree = "<group>"; };
+ 69F7CE540B8DCB3300D76871 /* basic_ui.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_ui.h; sourceTree = "<group>"; };
+ 69F7CE550B8DCB3300D76871 /* control_protocol.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = control_protocol.h; sourceTree = "<group>"; };
+ 69F7CE560B8DCB3300D76871 /* smpte.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = smpte.h; sourceTree = "<group>"; };
+ 69F7CE570B8DCB3300D76871 /* control_protocol.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = control_protocol.cc; sourceTree = "<group>"; };
+ 69F7CE590B8DCB3300D76871 /* smpte.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = smpte.cc; sourceTree = "<group>"; };
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ 8D07F2C80486CC7A007CD1D0 /* ardour.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ardour.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 698D9AB60B969A6F00C53B63 /* midi++.framework in Frameworks */,
+ 69B1B5500B8E80AD007E41C1 /* CoreAudio.framework in Frameworks */,
+ 696C91000B8D52F300D66CAF /* glibmm.framework in Frameworks */,
+ 696C91010B8D52F300D66CAF /* Jack.framework in Frameworks */,
+ 696C91020B8D52F300D66CAF /* lo.framework in Frameworks */,
+ 696C91030B8D52F300D66CAF /* LRdf.framework in Frameworks */,
+ 696C91040B8D52F300D66CAF /* Raptor.framework in Frameworks */,
+ 696C91050B8D52F300D66CAF /* SampleRate.framework in Frameworks */,
+ 696C91060B8D52F300D66CAF /* sigc.framework in Frameworks */,
+ 696C91070B8D52F300D66CAF /* Sndfile-ardour.framework in Frameworks */,
+ 696C91080B8D52F300D66CAF /* soundtouch.framework in Frameworks */,
+ 697D98090B8DCD8C0006A892 /* libxml2.dylib in Frameworks */,
+ 69B1B5210B8E7DFD007E41C1 /* pbd.framework in Frameworks */,
+ 696149E90B97CEF500ECBDF0 /* glib in Frameworks */,
+ 696149EA0B97CEF500ECBDF0 /* gmodule in Frameworks */,
+ 696149EB0B97CEF500ECBDF0 /* gobject in Frameworks */,
+ 696149EC0B97CEF500ECBDF0 /* gthread in Frameworks */,
+ 69AD45850B97D10600806E7E /* FLAC in Frameworks */,
+ 69DBC41B0BA794A500C19E65 /* Accelerate.framework in Frameworks */,
+ 69DBC42B0BA7992800C19E65 /* Carbon.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C80486CC7A007CD1D0 /* ardour.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* ardour */ = {
+ isa = PBXGroup;
+ children = (
+ 6964FEC80B8E7A7900799BAE /* version.h */,
+ 6964FEC90B8E7A7900799BAE /* version.cc */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 089C1665FE841158C02AAC07 /* Resources */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = ardour;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 69DBC42A0BA7992800C19E65 /* Carbon.framework */,
+ 69DBC41A0BA794A500C19E65 /* Accelerate.framework */,
+ 69AD45840B97D10600806E7E /* FLAC */,
+ 696149E50B97CEF500ECBDF0 /* glib */,
+ 696149E60B97CEF500ECBDF0 /* gmodule */,
+ 696149E70B97CEF500ECBDF0 /* gobject */,
+ 696149E80B97CEF500ECBDF0 /* gthread */,
+ 698D9AB00B969A5B00C53B63 /* midi++.xcodeproj */,
+ 69B1B54F0B8E80AD007E41C1 /* CoreAudio.framework */,
+ 697D98080B8DCD8C0006A892 /* libxml2.dylib */,
+ 691B3B770B8D5508009155B5 /* pbd.xcodeproj */,
+ 696C90F70B8D52F300D66CAF /* glibmm.framework */,
+ 696C90F80B8D52F300D66CAF /* Jack.framework */,
+ 696C90F90B8D52F300D66CAF /* lo.framework */,
+ 696C90FA0B8D52F300D66CAF /* LRdf.framework */,
+ 696C90FB0B8D52F300D66CAF /* Raptor.framework */,
+ 696C90FC0B8D52F300D66CAF /* SampleRate.framework */,
+ 696C90FD0B8D52F300D66CAF /* sigc.framework */,
+ 696C90FE0B8D52F300D66CAF /* Sndfile-ardour.framework */,
+ 696C90FF0B8D52F300D66CAF /* soundtouch.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C1665FE841158C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */,
+ 089C1666FE841158C02AAC07 /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 69F7CE510B8DCB3300D76871 /* control_protocol */,
+ 696C8FAD0B8D526000D66CAF /* ardour */,
+ 696C90020B8D526000D66CAF /* audio_diskstream.cc */,
+ 696C90030B8D526000D66CAF /* audio_library.cc */,
+ 696C90040B8D526000D66CAF /* audio_playlist.cc */,
+ 696C90050B8D526000D66CAF /* audio_track.cc */,
+ 696C90070B8D526000D66CAF /* audioengine.cc */,
+ 696C90080B8D526000D66CAF /* audiofilesource.cc */,
+ 696C90090B8D526000D66CAF /* audiofilter.cc */,
+ 696C900A0B8D526000D66CAF /* audioregion.cc */,
+ 696C900B0B8D526000D66CAF /* audiosource.cc */,
+ 696C900C0B8D526000D66CAF /* auditioner.cc */,
+ 696C900D0B8D526000D66CAF /* automation.cc */,
+ 696C900E0B8D526000D66CAF /* automation_event.cc */,
+ 696C900F0B8D526000D66CAF /* configuration.cc */,
+ 696C90100B8D526000D66CAF /* connection.cc */,
+ 696C90110B8D526000D66CAF /* control_protocol_manager.cc */,
+ 696C90130B8D526000D66CAF /* crossfade.cc */,
+ 696C90140B8D526000D66CAF /* curve.cc */,
+ 696C90150B8D526000D66CAF /* cycle_timer.cc */,
+ 696C90160B8D526000D66CAF /* default_click.cc */,
+ 696C90180B8D526000D66CAF /* diskstream.cc */,
+ 696C90190B8D526000D66CAF /* enums.cc */,
+ 696C901A0B8D526000D66CAF /* gain.cc */,
+ 696C901B0B8D526000D66CAF /* gdither.cc */,
+ 696C901C0B8D526000D66CAF /* gettext.h */,
+ 696C901D0B8D526000D66CAF /* globals.cc */,
+ 696C901E0B8D526000D66CAF /* i18n.h */,
+ 696C901F0B8D526000D66CAF /* import.cc */,
+ 696C90200B8D526000D66CAF /* insert.cc */,
+ 696C90210B8D526000D66CAF /* io.cc */,
+ 696C90220B8D526000D66CAF /* jack_slave.cc */,
+ 696C90230B8D526000D66CAF /* ladspa_plugin.cc */,
+ 696C90240B8D526000D66CAF /* location.cc */,
+ 696C90250B8D526000D66CAF /* mix.cc */,
+ 696C90260B8D526000D66CAF /* mtc_slave.cc */,
+ 696C90270B8D526000D66CAF /* named_selection.cc */,
+ 696C90280B8D526000D66CAF /* osc.cc */,
+ 696C90290B8D526000D66CAF /* panner.cc */,
+ 696C902A0B8D526000D66CAF /* pcm_utils.cc */,
+ 696C902B0B8D526000D66CAF /* playlist.cc */,
+ 696C902C0B8D526000D66CAF /* playlist_factory.cc */,
+ 696C902D0B8D526000D66CAF /* plugin.cc */,
+ 696C902E0B8D526000D66CAF /* plugin_manager.cc */,
+ 696C902F0B8D526000D66CAF /* port.cc */,
+ 696C90300B8D526000D66CAF /* recent_sessions.cc */,
+ 696C90310B8D526000D66CAF /* redirect.cc */,
+ 696C90320B8D526000D66CAF /* region.cc */,
+ 696C90330B8D526000D66CAF /* region_factory.cc */,
+ 696C90340B8D526000D66CAF /* reverse.cc */,
+ 696C90350B8D526000D66CAF /* route.cc */,
+ 696C90360B8D526000D66CAF /* route_group.cc */,
+ 696C90370B8D526000D66CAF /* send.cc */,
+ 696C90380B8D526000D66CAF /* session.cc */,
+ 696C90390B8D526000D66CAF /* session_butler.cc */,
+ 696C903A0B8D526000D66CAF /* session_click.cc */,
+ 696C903B0B8D526000D66CAF /* session_command.cc */,
+ 696C903D0B8D526000D66CAF /* session_events.cc */,
+ 696C903E0B8D526000D66CAF /* session_export.cc */,
+ 696C903F0B8D526000D66CAF /* session_feedback.cc */,
+ 696C90400B8D526000D66CAF /* session_midi.cc */,
+ 696C90410B8D526000D66CAF /* session_process.cc */,
+ 696C90420B8D526000D66CAF /* session_state.cc */,
+ 696C90430B8D526000D66CAF /* session_time.cc */,
+ 696C90440B8D526000D66CAF /* session_timefx.cc */,
+ 696C90450B8D526000D66CAF /* session_transport.cc */,
+ 696C90470B8D526000D66CAF /* silentfilesource.cc */,
+ 696C90480B8D526000D66CAF /* sndfile_helpers.cc */,
+ 696C90490B8D526000D66CAF /* sndfilesource.cc */,
+ 696C904A0B8D526000D66CAF /* source.cc */,
+ 696C904B0B8D526000D66CAF /* source_factory.cc */,
+ 696C904E0B8D526000D66CAF /* tempo.cc */,
+ 696C904F0B8D526000D66CAF /* track.cc */,
+ 696C90500B8D526000D66CAF /* utils.cc */,
+ 32BAE0B70371A74B00C91783 /* ardour_Prefix.pch */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 691B3B780B8D5508009155B5 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 691B3B7C0B8D5508009155B5 /* pbd.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 696C8FAD0B8D526000D66CAF /* ardour */ = {
+ isa = PBXGroup;
+ children = (
+ 696C8FAF0B8D526000D66CAF /* ardour.h */,
+ 696C8FB00B8D526000D66CAF /* audio_diskstream.h */,
+ 696C8FB10B8D526000D66CAF /* audio_library.h */,
+ 696C8FB20B8D526000D66CAF /* audio_track.h */,
+ 696C8FB40B8D526000D66CAF /* audioengine.h */,
+ 696C8FB50B8D526000D66CAF /* audiofilesource.h */,
+ 696C8FB60B8D526000D66CAF /* audiofilter.h */,
+ 696C8FB70B8D526000D66CAF /* audioplaylist.h */,
+ 696C8FB80B8D526000D66CAF /* audioregion.h */,
+ 696C8FB90B8D526000D66CAF /* audiosource.h */,
+ 696C8FBA0B8D526000D66CAF /* auditioner.h */,
+ 696C8FBB0B8D526000D66CAF /* automation_event.h */,
+ 696C8FBC0B8D526000D66CAF /* buffer.h */,
+ 696C8FBD0B8D526000D66CAF /* click.h */,
+ 696C8FBE0B8D526000D66CAF /* configuration.h */,
+ 696C8FBF0B8D526000D66CAF /* configuration_variable.h */,
+ 696C8FC00B8D526000D66CAF /* configuration_vars.h */,
+ 696C8FC10B8D526000D66CAF /* connection.h */,
+ 696C8FC20B8D526000D66CAF /* control_protocol_manager.h */,
+ 696C8FC40B8D526000D66CAF /* crossfade.h */,
+ 696C8FC50B8D526000D66CAF /* crossfade_compare.h */,
+ 696C8FC60B8D526000D66CAF /* curve.h */,
+ 696C8FC70B8D526000D66CAF /* cycle_timer.h */,
+ 696C8FC80B8D526000D66CAF /* cycles.h */,
+ 696C8FC90B8D526000D66CAF /* data_type.h */,
+ 696C8FCA0B8D526000D66CAF /* dB.h */,
+ 696C8FCC0B8D526000D66CAF /* diskstream.h */,
+ 696C8FCD0B8D526000D66CAF /* export.h */,
+ 696C8FCE0B8D526000D66CAF /* gain.h */,
+ 696C8FCF0B8D526000D66CAF /* gdither.h */,
+ 696C8FD00B8D526000D66CAF /* gdither_types.h */,
+ 696C8FD10B8D526000D66CAF /* gdither_types_internal.h */,
+ 696C8FD20B8D526000D66CAF /* insert.h */,
+ 696C8FD30B8D526000D66CAF /* io.h */,
+ 696C8FD40B8D526000D66CAF /* ladspa.h */,
+ 696C8FD50B8D526000D66CAF /* ladspa_plugin.h */,
+ 696C8FD60B8D526000D66CAF /* location.h */,
+ 696C8FD70B8D526000D66CAF /* logcurve.h */,
+ 696C8FD80B8D526000D66CAF /* mix.h */,
+ 696C8FD90B8D526000D66CAF /* named_selection.h */,
+ 696C8FDA0B8D526000D66CAF /* noise.h */,
+ 696C8FDB0B8D526000D66CAF /* osc.h */,
+ 696C8FDC0B8D526000D66CAF /* panner.h */,
+ 696C8FDD0B8D526000D66CAF /* pcm_utils.h */,
+ 696C8FDE0B8D526000D66CAF /* peak.h */,
+ 696C8FDF0B8D526000D66CAF /* playlist.h */,
+ 696C8FE00B8D526000D66CAF /* playlist_factory.h */,
+ 696C8FE10B8D526000D66CAF /* playlist_templates.h */,
+ 696C8FE20B8D526000D66CAF /* plugin.h */,
+ 696C8FE30B8D526000D66CAF /* plugin_manager.h */,
+ 696C8FE40B8D526000D66CAF /* port.h */,
+ 696C8FE50B8D526000D66CAF /* recent_sessions.h */,
+ 696C8FE60B8D526000D66CAF /* redirect.h */,
+ 696C8FE70B8D526000D66CAF /* region.h */,
+ 696C8FE80B8D526000D66CAF /* region_factory.h */,
+ 696C8FE90B8D526000D66CAF /* reverse.h */,
+ 696C8FEA0B8D526000D66CAF /* route.h */,
+ 696C8FEB0B8D526000D66CAF /* route_group.h */,
+ 696C8FEC0B8D526000D66CAF /* route_group_specialized.h */,
+ 696C8FED0B8D526000D66CAF /* send.h */,
+ 696C8FEE0B8D526000D66CAF /* session.h */,
+ 696C8FEF0B8D526000D66CAF /* session_connection.h */,
+ 696C8FF00B8D526000D66CAF /* session_playlist.h */,
+ 696C8FF10B8D526000D66CAF /* session_region.h */,
+ 696C8FF20B8D526000D66CAF /* session_route.h */,
+ 696C8FF30B8D526000D66CAF /* session_selection.h */,
+ 696C8FF40B8D526000D66CAF /* silentfilesource.h */,
+ 696C8FF50B8D526000D66CAF /* slave.h */,
+ 696C8FF60B8D526000D66CAF /* sndfile_helpers.h */,
+ 696C8FF70B8D526000D66CAF /* sndfilesource.h */,
+ 696C8FF80B8D526000D66CAF /* soundseq.h */,
+ 696C8FF90B8D526000D66CAF /* source.h */,
+ 696C8FFA0B8D526000D66CAF /* source_factory.h */,
+ 696C8FFB0B8D526000D66CAF /* spline.h */,
+ 696C8FFC0B8D526000D66CAF /* tempo.h */,
+ 696C8FFD0B8D526000D66CAF /* timestamps.h */,
+ 696C8FFE0B8D526000D66CAF /* track.h */,
+ 696C8FFF0B8D526000D66CAF /* types.h */,
+ 696C90000B8D526000D66CAF /* utils.h */,
+ );
+ name = ardour;
+ path = ../ardour;
+ sourceTree = SOURCE_ROOT;
+ };
+ 698D9AB10B969A5B00C53B63 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 698D9AB50B969A5B00C53B63 /* midi++.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 69F7CE510B8DCB3300D76871 /* control_protocol */ = {
+ isa = PBXGroup;
+ children = (
+ 69F7CE520B8DCB3300D76871 /* basic_ui.cc */,
+ 69F7CE530B8DCB3300D76871 /* control_protocol */,
+ 69F7CE570B8DCB3300D76871 /* control_protocol.cc */,
+ 69F7CE590B8DCB3300D76871 /* smpte.cc */,
+ );
+ name = control_protocol;
+ path = ../../surfaces/control_protocol;
+ sourceTree = SOURCE_ROOT;
+ };
+ 69F7CE530B8DCB3300D76871 /* control_protocol */ = {
+ isa = PBXGroup;
+ children = (
+ 69F7CE540B8DCB3300D76871 /* basic_ui.h */,
+ 69F7CE550B8DCB3300D76871 /* control_protocol.h */,
+ 69F7CE560B8DCB3300D76871 /* smpte.h */,
+ );
+ path = control_protocol;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D07F2BE0486CC7A007CD1D0 /* ardour_Prefix.pch in Headers */,
+ 696C90530B8D526000D66CAF /* ardour.h in Headers */,
+ 696C90540B8D526000D66CAF /* audio_diskstream.h in Headers */,
+ 696C90550B8D526000D66CAF /* audio_library.h in Headers */,
+ 696C90560B8D526000D66CAF /* audio_track.h in Headers */,
+ 696C90580B8D526000D66CAF /* audioengine.h in Headers */,
+ 696C90590B8D526000D66CAF /* audiofilesource.h in Headers */,
+ 696C905A0B8D526000D66CAF /* audiofilter.h in Headers */,
+ 696C905B0B8D526000D66CAF /* audioplaylist.h in Headers */,
+ 696C905C0B8D526000D66CAF /* audioregion.h in Headers */,
+ 696C905D0B8D526000D66CAF /* audiosource.h in Headers */,
+ 696C905E0B8D526000D66CAF /* auditioner.h in Headers */,
+ 696C905F0B8D526000D66CAF /* automation_event.h in Headers */,
+ 696C90600B8D526000D66CAF /* buffer.h in Headers */,
+ 696C90610B8D526000D66CAF /* click.h in Headers */,
+ 696C90620B8D526000D66CAF /* configuration.h in Headers */,
+ 696C90630B8D526000D66CAF /* configuration_variable.h in Headers */,
+ 696C90640B8D526000D66CAF /* configuration_vars.h in Headers */,
+ 696C90650B8D526000D66CAF /* connection.h in Headers */,
+ 696C90660B8D526000D66CAF /* control_protocol_manager.h in Headers */,
+ 696C90680B8D526000D66CAF /* crossfade.h in Headers */,
+ 696C90690B8D526000D66CAF /* crossfade_compare.h in Headers */,
+ 696C906A0B8D526000D66CAF /* curve.h in Headers */,
+ 696C906B0B8D526000D66CAF /* cycle_timer.h in Headers */,
+ 696C906C0B8D526000D66CAF /* cycles.h in Headers */,
+ 696C906D0B8D526000D66CAF /* data_type.h in Headers */,
+ 696C906E0B8D526000D66CAF /* dB.h in Headers */,
+ 696C90700B8D526000D66CAF /* diskstream.h in Headers */,
+ 696C90710B8D526000D66CAF /* export.h in Headers */,
+ 696C90720B8D526000D66CAF /* gain.h in Headers */,
+ 696C90730B8D526000D66CAF /* gdither.h in Headers */,
+ 696C90740B8D526000D66CAF /* gdither_types.h in Headers */,
+ 696C90750B8D526000D66CAF /* gdither_types_internal.h in Headers */,
+ 696C90760B8D526000D66CAF /* insert.h in Headers */,
+ 696C90770B8D526000D66CAF /* io.h in Headers */,
+ 696C90780B8D526000D66CAF /* ladspa.h in Headers */,
+ 696C90790B8D526000D66CAF /* ladspa_plugin.h in Headers */,
+ 696C907A0B8D526000D66CAF /* location.h in Headers */,
+ 696C907B0B8D526000D66CAF /* logcurve.h in Headers */,
+ 696C907C0B8D526000D66CAF /* mix.h in Headers */,
+ 696C907D0B8D526000D66CAF /* named_selection.h in Headers */,
+ 696C907E0B8D526000D66CAF /* noise.h in Headers */,
+ 696C907F0B8D526000D66CAF /* osc.h in Headers */,
+ 696C90800B8D526000D66CAF /* panner.h in Headers */,
+ 696C90810B8D526000D66CAF /* pcm_utils.h in Headers */,
+ 696C90820B8D526000D66CAF /* peak.h in Headers */,
+ 696C90830B8D526000D66CAF /* playlist.h in Headers */,
+ 696C90840B8D526000D66CAF /* playlist_factory.h in Headers */,
+ 696C90850B8D526000D66CAF /* playlist_templates.h in Headers */,
+ 696C90860B8D526000D66CAF /* plugin.h in Headers */,
+ 696C90870B8D526000D66CAF /* plugin_manager.h in Headers */,
+ 696C90880B8D526000D66CAF /* port.h in Headers */,
+ 696C90890B8D526000D66CAF /* recent_sessions.h in Headers */,
+ 696C908A0B8D526000D66CAF /* redirect.h in Headers */,
+ 696C908B0B8D526000D66CAF /* region.h in Headers */,
+ 696C908C0B8D526000D66CAF /* region_factory.h in Headers */,
+ 696C908D0B8D526000D66CAF /* reverse.h in Headers */,
+ 696C908E0B8D526000D66CAF /* route.h in Headers */,
+ 696C908F0B8D526000D66CAF /* route_group.h in Headers */,
+ 696C90900B8D526000D66CAF /* route_group_specialized.h in Headers */,
+ 696C90910B8D526000D66CAF /* send.h in Headers */,
+ 696C90920B8D526000D66CAF /* session.h in Headers */,
+ 696C90930B8D526000D66CAF /* session_connection.h in Headers */,
+ 696C90940B8D526000D66CAF /* session_playlist.h in Headers */,
+ 696C90950B8D526000D66CAF /* session_region.h in Headers */,
+ 696C90960B8D526000D66CAF /* session_route.h in Headers */,
+ 696C90970B8D526000D66CAF /* session_selection.h in Headers */,
+ 696C90980B8D526000D66CAF /* silentfilesource.h in Headers */,
+ 696C90990B8D526000D66CAF /* slave.h in Headers */,
+ 696C909A0B8D526000D66CAF /* sndfile_helpers.h in Headers */,
+ 696C909B0B8D526000D66CAF /* sndfilesource.h in Headers */,
+ 696C909C0B8D526000D66CAF /* soundseq.h in Headers */,
+ 696C909D0B8D526000D66CAF /* source.h in Headers */,
+ 696C909E0B8D526000D66CAF /* source_factory.h in Headers */,
+ 696C909F0B8D526000D66CAF /* spline.h in Headers */,
+ 696C90A00B8D526000D66CAF /* tempo.h in Headers */,
+ 696C90A10B8D526000D66CAF /* timestamps.h in Headers */,
+ 696C90A20B8D526000D66CAF /* track.h in Headers */,
+ 696C90A30B8D526000D66CAF /* types.h in Headers */,
+ 696C90A40B8D526000D66CAF /* utils.h in Headers */,
+ 696C90C00B8D526000D66CAF /* gettext.h in Headers */,
+ 696C90C20B8D526000D66CAF /* i18n.h in Headers */,
+ 69F7CE5B0B8DCB3300D76871 /* basic_ui.h in Headers */,
+ 69F7CE5C0B8DCB3300D76871 /* control_protocol.h in Headers */,
+ 69F7CE5D0B8DCB3300D76871 /* smpte.h in Headers */,
+ 6964FECA0B8E7A7900799BAE /* version.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 8D07F2BC0486CC7A007CD1D0 /* ardour */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "ardour" */;
+ buildPhases = (
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */,
+ 8D07F2C50486CC7A007CD1D0 /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 69D5F6260B8D58A500301E71 /* PBXTargetDependency */,
+ 698D9ABA0B969ADC00C53B63 /* PBXTargetDependency */,
+ );
+ name = ardour;
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = ardour;
+ productReference = 8D07F2C80486CC7A007CD1D0 /* ardour.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "ardour" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* ardour */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 698D9AB10B969A5B00C53B63 /* Products */;
+ ProjectRef = 698D9AB00B969A5B00C53B63 /* midi++.xcodeproj */;
+ },
+ {
+ ProductGroup = 691B3B780B8D5508009155B5 /* Products */;
+ ProjectRef = 691B3B770B8D5508009155B5 /* pbd.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* ardour */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 691B3B7C0B8D5508009155B5 /* pbd.framework */ = {
+ isa = PBXReferenceProxy;
+ fileType = wrapper.framework;
+ path = pbd.framework;
+ remoteRef = 691B3B7B0B8D5508009155B5 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 698D9AB50B969A5B00C53B63 /* midi++.framework */ = {
+ isa = PBXReferenceProxy;
+ fileType = wrapper.framework;
+ path = "midi++.framework";
+ remoteRef = 698D9AB40B969A5B00C53B63 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8D07F2C50486CC7A007CD1D0 /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 696C90A60B8D526000D66CAF /* audio_diskstream.cc in Sources */,
+ 696C90A70B8D526000D66CAF /* audio_library.cc in Sources */,
+ 696C90A80B8D526000D66CAF /* audio_playlist.cc in Sources */,
+ 696C90A90B8D526000D66CAF /* audio_track.cc in Sources */,
+ 696C90AB0B8D526000D66CAF /* audioengine.cc in Sources */,
+ 696C90AC0B8D526000D66CAF /* audiofilesource.cc in Sources */,
+ 696C90AD0B8D526000D66CAF /* audiofilter.cc in Sources */,
+ 696C90AE0B8D526000D66CAF /* audioregion.cc in Sources */,
+ 696C90AF0B8D526000D66CAF /* audiosource.cc in Sources */,
+ 696C90B00B8D526000D66CAF /* auditioner.cc in Sources */,
+ 696C90B10B8D526000D66CAF /* automation.cc in Sources */,
+ 696C90B20B8D526000D66CAF /* automation_event.cc in Sources */,
+ 696C90B30B8D526000D66CAF /* configuration.cc in Sources */,
+ 696C90B40B8D526000D66CAF /* connection.cc in Sources */,
+ 696C90B50B8D526000D66CAF /* control_protocol_manager.cc in Sources */,
+ 696C90B70B8D526000D66CAF /* crossfade.cc in Sources */,
+ 696C90B80B8D526000D66CAF /* curve.cc in Sources */,
+ 696C90B90B8D526000D66CAF /* cycle_timer.cc in Sources */,
+ 696C90BA0B8D526000D66CAF /* default_click.cc in Sources */,
+ 696C90BC0B8D526000D66CAF /* diskstream.cc in Sources */,
+ 696C90BD0B8D526000D66CAF /* enums.cc in Sources */,
+ 696C90BE0B8D526000D66CAF /* gain.cc in Sources */,
+ 696C90BF0B8D526000D66CAF /* gdither.cc in Sources */,
+ 696C90C10B8D526000D66CAF /* globals.cc in Sources */,
+ 696C90C30B8D526000D66CAF /* import.cc in Sources */,
+ 696C90C40B8D526000D66CAF /* insert.cc in Sources */,
+ 696C90C50B8D526000D66CAF /* io.cc in Sources */,
+ 696C90C60B8D526000D66CAF /* jack_slave.cc in Sources */,
+ 696C90C70B8D526000D66CAF /* ladspa_plugin.cc in Sources */,
+ 696C90C80B8D526000D66CAF /* location.cc in Sources */,
+ 696C90C90B8D526000D66CAF /* mix.cc in Sources */,
+ 696C90CA0B8D526000D66CAF /* mtc_slave.cc in Sources */,
+ 696C90CB0B8D526000D66CAF /* named_selection.cc in Sources */,
+ 696C90CC0B8D526000D66CAF /* osc.cc in Sources */,
+ 696C90CD0B8D526000D66CAF /* panner.cc in Sources */,
+ 696C90CE0B8D526000D66CAF /* pcm_utils.cc in Sources */,
+ 696C90CF0B8D526000D66CAF /* playlist.cc in Sources */,
+ 696C90D00B8D526000D66CAF /* playlist_factory.cc in Sources */,
+ 696C90D10B8D526000D66CAF /* plugin.cc in Sources */,
+ 696C90D20B8D526000D66CAF /* plugin_manager.cc in Sources */,
+ 696C90D30B8D526000D66CAF /* port.cc in Sources */,
+ 696C90D40B8D526000D66CAF /* recent_sessions.cc in Sources */,
+ 696C90D50B8D526000D66CAF /* redirect.cc in Sources */,
+ 696C90D60B8D526000D66CAF /* region.cc in Sources */,
+ 696C90D70B8D526000D66CAF /* region_factory.cc in Sources */,
+ 696C90D80B8D526000D66CAF /* reverse.cc in Sources */,
+ 696C90D90B8D526000D66CAF /* route.cc in Sources */,
+ 696C90DA0B8D526000D66CAF /* route_group.cc in Sources */,
+ 696C90DB0B8D526000D66CAF /* send.cc in Sources */,
+ 696C90DC0B8D526000D66CAF /* session.cc in Sources */,
+ 696C90DD0B8D526000D66CAF /* session_butler.cc in Sources */,
+ 696C90DE0B8D526000D66CAF /* session_click.cc in Sources */,
+ 696C90DF0B8D526000D66CAF /* session_command.cc in Sources */,
+ 696C90E10B8D526000D66CAF /* session_events.cc in Sources */,
+ 696C90E20B8D526000D66CAF /* session_export.cc in Sources */,
+ 696C90E30B8D526000D66CAF /* session_feedback.cc in Sources */,
+ 696C90E40B8D526000D66CAF /* session_midi.cc in Sources */,
+ 696C90E50B8D526000D66CAF /* session_process.cc in Sources */,
+ 696C90E60B8D526000D66CAF /* session_state.cc in Sources */,
+ 696C90E70B8D526000D66CAF /* session_time.cc in Sources */,
+ 696C90E80B8D526000D66CAF /* session_timefx.cc in Sources */,
+ 696C90E90B8D526000D66CAF /* session_transport.cc in Sources */,
+ 696C90EB0B8D526000D66CAF /* silentfilesource.cc in Sources */,
+ 696C90EC0B8D526000D66CAF /* sndfile_helpers.cc in Sources */,
+ 696C90ED0B8D526000D66CAF /* sndfilesource.cc in Sources */,
+ 696C90EE0B8D526000D66CAF /* source.cc in Sources */,
+ 696C90EF0B8D526000D66CAF /* source_factory.cc in Sources */,
+ 696C90F20B8D526000D66CAF /* tempo.cc in Sources */,
+ 696C90F30B8D526000D66CAF /* track.cc in Sources */,
+ 696C90F40B8D526000D66CAF /* utils.cc in Sources */,
+ 69F7CE5A0B8DCB3300D76871 /* basic_ui.cc in Sources */,
+ 69F7CE5E0B8DCB3300D76871 /* control_protocol.cc in Sources */,
+ 69F7CE600B8DCB3300D76871 /* smpte.cc in Sources */,
+ 6964FECB0B8E7A7900799BAE /* version.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 698D9ABA0B969ADC00C53B63 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = "midi++";
+ targetProxy = 698D9AB90B969ADC00C53B63 /* PBXContainerItemProxy */;
+ };
+ 69D5F6260B8D58A500301E71 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = pbd;
+ targetProxy = 69D5F6250B8D58A500301E71 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 089C1667FE841158C02AAC07 /* English */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ DEBUG_INFORMATION_FORMAT = stabs;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
+ "$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
+ );
+ FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SYSTEM_DEVELOPER_DIR)/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks\"";
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = ardour_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_2)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_2 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/Sndfile-ardour.framework/Versions/A/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/Sndfile-ardour.framework/Versions/A/Libraries\"";
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ PRODUCT_NAME = ardour;
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Release;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ "$(NATIVE_ARCH)",
+ ppc,
+ );
+ FRAMEWORK_SEARCH_PATHS = /opt/ardour/build;
+ GCC_FAST_OBJC_DISPATCH = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G4;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ BUILD_VECLIB_OPTIMIZATIONS,
+ HAVE_WORDEXP,
+ HAVE_WEAK_COREAUDIO,
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_2)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_3)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_4)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_5)",
+ NO_POSIX_MEMALIGN,
+ );
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1 = "PACKAGE=\"\\\"libardour\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_2 = "CONFIG_DIR=\"\\\"/Library/Application\\ Support/Ardour/config\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_3 = "MODULE_DIR=\"\\\"/Library/Application\\ Support/Ardour/modules\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_4 = "DATA_DIR=\"\\\"/Library/Application\\ Support/Ardour/data\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_5 = "LOCALEDIR=\"\\\"/Library/Application\\ Support/Ardour/locales\\\"\"";
+ GCC_STRICT_ALIASING = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ /usr/include/libxml2,
+ /Library/Frameworks/sigc.framework/Headers,
+ /Library/Frameworks/GLib.framework/Headers,
+ /Library/Frameworks/glibmm.framework/Headers,
+ "/Library/Frameworks/Sndfile-ardour.framework/Headers",
+ /Library/Frameworks/SampleRate.framework/Headers,
+ /Library/Frameworks/Raptor.framework/Headers,
+ /Library/Frameworks/LRdf.framework/Headers,
+ /opt/ardour/src/ardour2/libs/surfaces/control_protocol,
+ );
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+ 694E7C8A0B97B0FE0018D03D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(NATIVE_ARCH)";
+ COPY_PHASE_STRIP = NO;
+ FRAMEWORK_SEARCH_PATHS = /opt/ardour/build;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_ENABLE_OBJC_EXCEPTIONS = NO;
+ GCC_FAST_OBJC_DISPATCH = NO;
+ GCC_MODEL_TUNING = G4;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ BUILD_VECLIB_OPTIMIZATIONS,
+ HAVE_WORDEXP,
+ HAVE_WEAK_COREAUDIO,
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_2)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_3)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_4)",
+ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_5)",
+ NO_POSIX_MEMALIGN,
+ );
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1 = "PACKAGE=\"\\\"libardour\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_2 = "CONFIG_DIR=\"\\\"/Library/Application\\ Support/Ardour/config\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_3 = "MODULE_DIR=\"\\\"/Library/Application\\ Support/Ardour/modules\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_4 = "DATA_DIR=\"\\\"/Library/Application\\ Support/Ardour/data\\\"\"";
+ GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_5 = "LOCALEDIR=\"\\\"/Library/Application\\ Support/Ardour/locales\\\"\"";
+ GCC_STRICT_ALIASING = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ /usr/include/libxml2,
+ /Library/Frameworks/sigc.framework/Headers,
+ /Library/Frameworks/GLib.framework/Headers,
+ /Library/Frameworks/glibmm.framework/Headers,
+ "/Library/Frameworks/Sndfile-ardour.framework/Headers",
+ /Library/Frameworks/SampleRate.framework/Headers,
+ /Library/Frameworks/Raptor.framework/Headers,
+ /Library/Frameworks/LRdf.framework/Headers,
+ /opt/ardour/src/ardour2/libs/surfaces/control_protocol,
+ );
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ STRIP_INSTALLED_PRODUCT = NO;
+ };
+ name = Debug;
+ };
+ 694E7C8B0B97B0FE0018D03D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = i386;
+ DEBUG_INFORMATION_FORMAT = stabs;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
+ "$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
+ );
+ FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SYSTEM_DEVELOPER_DIR)/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks\"";
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = ardour_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_4)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/Sndfile-ardour.framework/Versions/A/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_4 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/Sndfile-ardour.framework/Versions/A/Libraries\"";
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ PRODUCT_NAME = ardour;
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "ardour" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24408B4156D00ABE55E /* Release */,
+ 694E7C8B0B97B0FE0018D03D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "ardour" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24808B4156D00ABE55E /* Release */,
+ 694E7C8A0B97B0FE0018D03D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/libs/ardour/macosx/ardour_Prefix.pch b/libs/ardour/macosx/ardour_Prefix.pch
new file mode 100644
index 0000000000..b03e5d3d98
--- /dev/null
+++ b/libs/ardour/macosx/ardour_Prefix.pch
@@ -0,0 +1,4 @@
+//
+// Prefix header for all source files of the 'ardour' target in the 'ardour' project.
+//
+
diff --git a/libs/ardour/macosx/version.cc b/libs/ardour/macosx/version.cc
new file mode 100644
index 0000000000..9da3d2c359
--- /dev/null
+++ b/libs/ardour/macosx/version.cc
@@ -0,0 +1,3 @@
+int libardour_major_version = 2;
+int libardour_minor_version = 0;
+int libardour_micro_version = 0;
diff --git a/libs/ardour/macosx/version.h b/libs/ardour/macosx/version.h
new file mode 100644
index 0000000000..9c575ee077
--- /dev/null
+++ b/libs/ardour/macosx/version.h
@@ -0,0 +1,17 @@
+/*
+ * version.h
+ * ardour
+ *
+ * Created by Taybin Rutkin on 2/22/07.
+ * Copyright 2007 Paul Davis. All rights reserved.
+ *
+ */
+
+#ifndef __libardour_version_h__
+#define __libardour_version_h__
+
+extern int libardour_major_version;
+extern int libardour_minor_version;
+extern int libardour_micro_version;
+
+#endif /* __libardour_version_h__ */
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index b11e3f3062..06b75211f7 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -42,7 +42,6 @@
#include <ardour/utils.h>
#include <ardour/configuration.h>
#include <ardour/smf_source.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/send.h>
#include <ardour/region_factory.h>
#include <ardour/midi_playlist.h>
diff --git a/libs/ardour/mix.cc b/libs/ardour/mix.cc
index 6b7755e498..2d31c8ccc8 100644
--- a/libs/ardour/mix.cc
+++ b/libs/ardour/mix.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
@@ -25,7 +24,6 @@
#include <stdint.h>
#if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
-
// Debug wrappers
float
@@ -92,6 +90,25 @@ compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current)
}
void
+find_peaks (ARDOUR::Sample *buf, nframes_t nframes, float *min, float *max)
+{
+ nframes_t i;
+ float a, b;
+
+ a = *max;
+ b = *min;
+
+ for (i = 0; i < nframes; i++)
+ {
+ a = fmax (buf[i], a);
+ b = fmin (buf[i], b);
+ }
+
+ *max = a;
+ *min = b;
+}
+
+void
apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain)
{
for (nframes_t i=0; i<nframes; i++)
@@ -126,6 +143,13 @@ veclib_compute_peak (ARDOUR::Sample *buf, nframes_t nsamples, float current)
}
void
+veclib_find_peaks (ARDOUR::Sample *buf, nframes_t nframes, float *min, float *max)
+{
+ vDSP_maxv (buf, 1, max, nframes);
+ vDSP_minv (buf, 1, min, nframes);
+}
+
+void
veclib_apply_gain_to_buffer (ARDOUR::Sample *buf, nframes_t nframes, float gain)
{
vDSP_vsmul(buf, 1, &gain, buf, 1, nframes);
diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc
index 2b4b2ae5bf..3447a92ce4 100644
--- a/libs/ardour/mtc_slave.cc
+++ b/libs/ardour/mtc_slave.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <errno.h>
@@ -42,6 +41,8 @@ using namespace PBD;
MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
: session (s)
{
+ can_notify_on_unknown_rate = true;
+
rebind (p);
reset ();
}
@@ -94,8 +95,39 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
smpte.minutes = msg[2];
smpte.seconds = msg[1];
smpte.frames = msg[0];
-
- session.smpte_to_sample( smpte, mtc_frame, true, false );
+
+ switch (msg[4]) {
+ case MTC_24_FPS:
+ smpte.rate = 24;
+ smpte.drop = false;
+ can_notify_on_unknown_rate = true;
+ break;
+ case MTC_25_FPS:
+ smpte.rate = 25;
+ smpte.drop = false;
+ can_notify_on_unknown_rate = true;
+ break;
+ case MTC_30_FPS_DROP:
+ smpte.rate = 30;
+ smpte.drop = true;
+ can_notify_on_unknown_rate = true;
+ break;
+ case MTC_30_FPS:
+ smpte.rate = 30;
+ smpte.drop = false;
+ can_notify_on_unknown_rate = true;
+ break;
+ default:
+ /* throttle error messages about unknown MTC rates */
+ if (can_notify_on_unknown_rate) {
+ error << _("Unknown rate/drop value in incoming MTC stream, session values used instead") << endmsg;
+ can_notify_on_unknown_rate = false;
+ }
+ smpte.rate = session.smpte_frames_per_second();
+ smpte.drop = session.smpte_drop_frames();
+ }
+
+ session.smpte_to_sample (smpte, mtc_frame, true, false);
if (was_full) {
diff --git a/libs/ardour/named_selection.cc b/libs/ardour/named_selection.cc
index b5a71f6403..fbb4b748df 100644
--- a/libs/ardour/named_selection.cc
+++ b/libs/ardour/named_selection.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <pbd/failed_constructor.h>
diff --git a/libs/ardour/osc.cc b/libs/ardour/osc.cc
index 933fba8740..d999386005 100644
--- a/libs/ardour/osc.cc
+++ b/libs/ardour/osc.cc
@@ -15,7 +15,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * $Id$
*/
#include <iostream>
@@ -59,6 +58,11 @@ int
OSC::start ()
{
char tmpstr[255];
+
+ if (_osc_server) {
+ /* already started */
+ return 0;
+ }
for (int j=0; j < 20; ++j) {
snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
@@ -109,16 +113,22 @@ OSC::start ()
int
OSC::stop ()
{
+ if (_osc_server == 0) {
+ /* already stopped */
+ return 0;
+ }
+
+ // stop server thread
+ terminate_osc_thread();
+
lo_server_free (_osc_server);
+ _osc_server = 0;
if (!_osc_unix_socket_path.empty()) {
// unlink it
unlink(_osc_unix_socket_path.c_str());
}
- // stop server thread
- terminate_osc_thread();
-
return 0;
}
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index 8ba662aaf4..8e41e70687 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS 1
diff --git a/libs/ardour/pcm_utils.cc b/libs/ardour/pcm_utils.cc
index dd18fe8690..08d8a63d6e 100644
--- a/libs/ardour/pcm_utils.cc
+++ b/libs/ardour/pcm_utils.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <ardour/pcm_utils.h>
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index db84b015bb..325ef27a18 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <set>
@@ -1517,17 +1516,33 @@ Playlist::bump_name_once (string name)
string newname;
if ((period = name.find_last_of ('.')) == string::npos) {
- newname = name;
+ newname = name;
newname += ".1";
} else {
- char buf[32];
- int version;
-
- sscanf (name.substr (period+1).c_str(), "%d", &version);
- snprintf (buf, sizeof(buf), "%d", version+1);
+ int isnumber = 1;
+ const char *last_element = name.c_str() + period + 1;
+ for (size_t i = 0; i < strlen(last_element); i++) {
+ if (!isdigit(last_element[i])) {
+ isnumber = 0;
+ break;
+ }
+ }
+
+ errno = 0;
+ long int version = strtol (name.c_str()+period+1, (char **)NULL, 10);
+
+ if (isnumber == 0 || errno != 0) {
+ // last_element is not a number, or is too large
+ newname = name;
+ newname += ".1";
+ } else {
+ char buf[32];
+
+ snprintf (buf, sizeof(buf), "%ld", version+1);
- newname = name.substr (0, period+1);
- newname += buf;
+ newname = name.substr (0, period+1);
+ newname += buf;
+ }
}
return newname;
diff --git a/libs/ardour/playlist_factory.cc b/libs/ardour/playlist_factory.cc
index 862f85a402..a801bae76c 100644
--- a/libs/ardour/playlist_factory.cc
+++ b/libs/ardour/playlist_factory.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <pbd/error.h>
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index 3b471014eb..b1fb43fc8f 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <vector>
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index 09da4c9ca7..9af7ad0451 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS 1
diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc
index 9e77128e4c..d9c93c250b 100644
--- a/libs/ardour/port.cc
+++ b/libs/ardour/port.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <ardour/port.h>
diff --git a/libs/ardour/redirect.cc b/libs/ardour/redirect.cc
index dbdd3d1ddd..ba895f6447 100644
--- a/libs/ardour/redirect.cc
+++ b/libs/ardour/redirect.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <fstream>
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 973e14fd31..15609706b2 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <iostream>
@@ -888,7 +887,7 @@ Region::state (bool full_state)
{
XMLNode *node = new XMLNode ("Region");
char buf[64];
- char* fe;
+ char* fe = NULL;
_id.print (buf, sizeof (buf));
node->add_property ("id", buf);
@@ -911,6 +910,10 @@ Region::state (bool full_state)
case EditChangesID:
fe = X_("id");
break;
+ default: /* should be unreachable but makes g++ happy */
+ cerr << "Odd region property found\n";
+ fe = X_("nothing");
+ break;
}
node->add_property ("first_edit", fe);
diff --git a/libs/ardour/region_factory.cc b/libs/ardour/region_factory.cc
index 4041852f4e..a0aa3be759 100644
--- a/libs/ardour/region_factory.cc
+++ b/libs/ardour/region_factory.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: playlist_factory.cc 629 2006-06-21 23:01:03Z paul $
*/
#include <pbd/error.h>
diff --git a/libs/ardour/reverse.cc b/libs/ardour/reverse.cc
index 2279331701..c7ebecea31 100644
--- a/libs/ardour/reverse.cc
+++ b/libs/ardour/reverse.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
@@ -47,10 +46,9 @@ Reverse::run (boost::shared_ptr<AudioRegion> region)
{
SourceList nsrcs;
SourceList::iterator si;
- const nframes_t blocksize = 256 * 1048;
- Sample buf[blocksize];
+ nframes_t blocksize = 256 * 1024;
+ Sample* buf = 0;
nframes_t fpos;
- nframes_t fend;
nframes_t fstart;
nframes_t to_read;
int ret = -1;
@@ -61,20 +59,19 @@ Reverse::run (boost::shared_ptr<AudioRegion> region)
goto out;
}
- fend = region->start() + region->length();
fstart = region->start();
- if (blocksize < fend) {
- fpos =max(fstart, fend - blocksize);
- } else {
- fpos = fstart;
+ if (blocksize > region->length()) {
+ blocksize = region->length();
}
- to_read = min (region->length(), blocksize);
+ fpos = max (fstart, (fstart + region->length() - blocksize));
+ buf = new Sample[blocksize];
+ to_read = blocksize;
/* now read it backwards */
- while (1) {
+ while (to_read) {
uint32_t n;
@@ -85,7 +82,7 @@ Reverse::run (boost::shared_ptr<AudioRegion> region)
if (region->audio_source (n)->read (buf, fpos, to_read) != to_read) {
goto out;
}
-
+
/* swap memory order */
for (nframes_t i = 0; i < to_read/2; ++i) {
@@ -101,13 +98,11 @@ Reverse::run (boost::shared_ptr<AudioRegion> region)
}
}
- if (fpos == fstart) {
- break;
- } else if (fpos > fstart + to_read) {
+ if (fpos > fstart + blocksize) {
fpos -= to_read;
- to_read = min (fstart - fpos, blocksize);
+ to_read = blocksize;
} else {
- to_read = fpos-fstart;
+ to_read = fpos - fstart;
fpos = fstart;
}
};
@@ -116,6 +111,10 @@ Reverse::run (boost::shared_ptr<AudioRegion> region)
out:
+ if (buf) {
+ delete [] buf;
+ }
+
if (ret) {
for (si = nsrcs.begin(); si != nsrcs.end(); ++si) {
boost::shared_ptr<AudioSource> asrc(boost::dynamic_pointer_cast<AudioSource>(*si));
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index d415741831..43c233e4d7 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
@@ -81,7 +80,7 @@ Route::init ()
_soloed = false;
_solo_safe = false;
_phase_invert = false;
- order_keys[N_("signal")] = order_key_cnt++;
+ order_keys[strdup (N_("signal"))] = order_key_cnt++;
_active = true;
_silent = false;
_meter_point = MeterPostFader;
@@ -116,6 +115,10 @@ Route::~Route ()
{
clear_redirects (this);
+ for (OrderKeys::iterator i = order_keys.begin(); i != order_keys.end(); ++i) {
+ free ((void*)(i->first));
+ }
+
if (_control_outs) {
delete _control_outs;
}
@@ -137,21 +140,23 @@ Route::remote_control_id() const
}
long
-Route::order_key (string name) const
+Route::order_key (const char* name) const
{
OrderKeys::const_iterator i;
- if ((i = order_keys.find (name)) == order_keys.end()) {
- return -1;
+ for (i = order_keys.begin(); i != order_keys.end(); ++i) {
+ if (!strcmp (name, i->first)) {
+ return i->second;
+ }
}
- return (*i).second;
+ return -1;
}
void
-Route::set_order_key (string name, long n)
+Route::set_order_key (const char* name, long n)
{
- order_keys[name] = n;
+ order_keys[strdup(name)] = n;
_session.set_dirty ();
}
@@ -1107,9 +1112,16 @@ Route::_reset_plugin_counts (uint32_t* err_streams)
} else {
s->expect_inputs ((*prev)->output_streams());
}
- }
- redirect_max_outs = max ((*r)->output_streams(), redirect_max_outs);
+ } else {
+
+ /* don't pay any attention to send output configuration, since it doesn't
+ affect the route.
+ */
+
+ redirect_max_outs = max ((*r)->output_streams (), redirect_max_outs);
+
+ }
}
/* we're done */
@@ -1349,7 +1361,7 @@ Route::state(bool full_state)
OrderKeys::iterator x = order_keys.begin();
while (x != order_keys.end()) {
- order_string += (*x).first;
+ order_string += string ((*x).first);
order_string += '=';
snprintf (buf, sizeof(buf), "%ld", (*x).second);
order_string += buf;
@@ -1368,6 +1380,11 @@ Route::state(bool full_state)
node->add_child_nocopy (_solo_control.get_state ());
node->add_child_nocopy (_mute_control.get_state ());
+ 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);
+ node->add_child_nocopy (*remote_control_node);
+
if (_control_outs) {
XMLNode* cnode = new XMLNode (X_("ControlOuts"));
cnode->add_child_nocopy (_control_outs->state (full_state));
@@ -1564,7 +1581,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining)
<< endmsg;
} else {
- set_order_key (remaining.substr (0, equal), n);
+ set_order_key (remaining.substr (0, equal).c_str(), n);
}
}
@@ -1661,6 +1678,13 @@ Route::_set_state (const XMLNode& node, bool call_base)
_session.add_controllable (&_mute_control);
}
}
+ else if (child->name() == X_("remote_control")) {
+ if ((prop = child->property (X_("id"))) != 0) {
+ int32_t x;
+ sscanf (prop->value().c_str(), "%d", &x);
+ set_remote_control_id (x);
+ }
+ }
}
if ((prop = node.property (X_("mix-group"))) != 0) {
diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc
index c2aa59ed8b..13b90474cc 100644
--- a/libs/ardour/route_group.cc
+++ b/libs/ardour/route_group.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index 0141007803..39c917571a 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 764b25dc9b..9d0b13fccd 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
@@ -54,7 +53,6 @@
#include <ardour/midi_playlist.h>
#include <ardour/midi_region.h>
#include <ardour/smf_source.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/auditioner.h>
#include <ardour/recent_sessions.h>
#include <ardour/redirect.h>
@@ -86,6 +84,12 @@ using namespace ARDOUR;
using namespace PBD;
using boost::shared_ptr;
+#ifdef __x86_64__
+static const int CPU_CACHE_ALIGN = 64;
+#else
+static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
+#endif
+
const char* Session::_template_suffix = X_(".template");
const char* Session::_statefile_suffix = X_(".ardour");
const char* Session::_pending_suffix = X_(".pending");
@@ -94,8 +98,10 @@ const char* Session::sound_dir_name = X_("audiofiles");
const char* Session::peak_dir_name = X_("peaks");
const char* Session::dead_sound_dir_name = X_("dead_sounds");
const char* Session::interchange_dir_name = X_("interchange");
+const char* Session::export_dir_name = X_("export");
-Session::compute_peak_t Session::compute_peak = 0;
+Session::compute_peak_t Session::compute_peak = 0;
+Session::find_peaks_t Session::find_peaks = 0;
Session::apply_gain_to_buffer_t Session::apply_gain_to_buffer = 0;
Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0;
Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0;
@@ -280,6 +286,10 @@ Session::Session (AudioEngine &eng,
{
bool new_session;
+ if (!eng.connected()) {
+ throw failed_constructor();
+ }
+
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
n_physical_outputs = _engine.n_physical_outputs();
@@ -342,6 +352,10 @@ Session::Session (AudioEngine &eng,
{
bool new_session;
+ if (!eng.connected()) {
+ throw failed_constructor();
+ }
+
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
n_physical_outputs = _engine.n_physical_outputs();
@@ -1396,7 +1410,7 @@ Session::set_block_size (nframes_t nframes)
{
current_block_size = nframes;
-
+
ensure_buffers(_scratch_buffers->available());
if (_gain_automation_buffer) {
@@ -1740,16 +1754,19 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
} else {
nphysical_out = 0;
}
+
+ shared_ptr<AudioTrack> track;
try {
- shared_ptr<AudioTrack> track (new AudioTrack (*this, track_name, Route::Flag (0), mode));
+ track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
+ goto failed;
}
-
+
if (nphysical_in) {
for (uint32_t x = 0; x < track->n_inputs().get(DataType::AUDIO) && x < nphysical_in; ++x) {
@@ -1809,14 +1826,43 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
catch (failed_constructor &err) {
error << _("Session: could not create new audio track.") << endmsg;
- // XXX should we delete the tracks already created?
- ret.clear ();
- return ret;
+
+ if (track) {
+ /* we need to get rid of this, since the track failed to be created */
+ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
+
+ {
+ RCUWriter<DiskstreamList> writer (diskstreams);
+ boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
+ ds->remove (track->audio_diskstream());
+ }
+ }
+
+ goto failed;
}
-
+
+ catch (AudioEngine::PortRegistrationFailure& pfe) {
+
+ error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
+
+ if (track) {
+ /* we need to get rid of this, since the track failed to be created */
+ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
+
+ {
+ RCUWriter<DiskstreamList> writer (diskstreams);
+ boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
+ ds->remove (track->audio_diskstream());
+ }
+ }
+
+ goto failed;
+ }
+
--how_many;
}
+ failed:
if (!new_routes.empty()) {
add_routes (new_routes, false);
save_state (_current_snapshot_name);
@@ -1825,6 +1871,27 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
return ret;
}
+void
+Session::set_remote_control_ids ()
+{
+ RemoteModel m = Config->get_remote_model();
+
+ shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if ( MixerOrdered == m) {
+ long order = (*i)->order_key(N_("signal"));
+ (*i)->set_remote_control_id( order+1 );
+ } else if ( EditorOrdered == m) {
+ long order = (*i)->order_key(N_("editor"));
+ (*i)->set_remote_control_id( order+1 );
+ } else if ( UserOrdered == m) {
+ //do nothing ... only changes to remote id's are initiated by user
+ }
+ }
+}
+
+
Session::RouteList
Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
{
@@ -1876,6 +1943,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
+ goto failure;
}
for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().get(DataType::AUDIO); ++x) {
@@ -1927,13 +1995,19 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
catch (failed_constructor &err) {
error << _("Session: could not create new audio route.") << endmsg;
- ret.clear ();
- return ret;
+ goto failure;
+ }
+
+ catch (AudioEngine::PortRegistrationFailure& pfe) {
+ error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
+ goto failure;
}
+
--how_many;
}
+ failure:
if (!ret.empty()) {
add_routes (ret, false);
save_state (_current_snapshot_name);
@@ -1984,21 +2058,23 @@ void
Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
{
/* need to do this in case we're rolling at the time, to prevent false underruns */
- dstream->do_refill_with_alloc();
+ dstream->do_refill_with_alloc ();
- {
+ dstream->set_block_size (current_block_size);
+
+ {
RCUWriter<DiskstreamList> writer (diskstreams);
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->push_back (dstream);
- }
-
- dstream->set_block_size (current_block_size);
+ /* writer goes out of scope, copies ds back to main */
+ }
dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream));
/* this will connect to future changes, and check the current length */
diskstream_playlist_changed (dstream);
dstream->prepare ();
+
}
void
@@ -2180,9 +2256,11 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
modify_solo_mute (is_track, same_thing_soloed);
if (signal) {
- SoloActive (currently_soloing);
+ SoloActive (currently_soloing); /* EMIT SIGNAL */
}
+ SoloChanged (); /* EMIT SIGNAL */
+
set_dirty();
}
@@ -2797,6 +2875,24 @@ Session::source_by_id (const PBD::ID& id)
return source;
}
+
+boost::shared_ptr<Source>
+Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
+{
+ Glib::Mutex::Lock lm (source_lock);
+
+ for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
+ cerr << "comparing " << path << " with " << i->second->name() << endl;
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
+
+ if (afs && afs->path() == path && chn == afs->channel()) {
+ return afs;
+ }
+
+ }
+ return boost::shared_ptr<Source>();
+}
+
string
Session::peak_path_from_audio_path (string audio_path) const
{
@@ -3503,7 +3599,7 @@ void
Session::graph_reordered ()
{
/* don't do this stuff if we are setting up connections
- from a set_state() call.
+ from a set_state() call or creating new tracks.
*/
if (_state_of_the_state & InitialConnecting) {
@@ -3630,11 +3726,11 @@ Session::available_capture_duration ()
switch (Config->get_native_file_data_format()) {
case FormatFloat:
- sample_bytes_on_disk = 4;
+ sample_bytes_on_disk = 4.0;
break;
case FormatInt24:
- sample_bytes_on_disk = 3;
+ sample_bytes_on_disk = 3.0;
break;
default:
@@ -3733,7 +3829,6 @@ Session::next_insert_id ()
for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < insert_bitset.size(); ++n) {
if (!insert_bitset[n]) {
insert_bitset[n] = true;
- cerr << "Returning " << n << " as insert ID\n";
return n;
}
@@ -3754,7 +3849,6 @@ Session::next_send_id ()
for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < send_bitset.size(); ++n) {
if (!send_bitset[n]) {
send_bitset[n] = true;
- cerr << "Returning " << n << " as send ID\n";
return n;
}
@@ -3991,6 +4085,12 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
buffers.ensure_buffers(nchans, chunk_size);
buffers.set_count(nchans);
+ for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
+ if (afs)
+ afs->prepare_for_peakfile_writes ();
+ }
+
while (to_do && !itt.cancel) {
this_chunk = min (to_do, chunk_size);
@@ -4029,18 +4129,10 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
if (afs) {
afs->update_header (position, *xnow, now);
+ afs->flush_header ();
}
}
- /* build peakfile for new source */
-
- for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
- if (afs) {
- afs->build_peaks ();
- }
- }
-
/* construct a region to represent the bounced material */
boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
@@ -4060,6 +4152,14 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
(*src)->drop_references ();
}
+
+ } else {
+ for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
+
+ if (afs)
+ afs->done_with_peakfile_writes ();
+ }
}
g_atomic_int_set (&processing_prohibited, 0);
diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc
index bb02eede91..16c8d9cffa 100644
--- a/libs/ardour/session_butler.cc
+++ b/libs/ardour/session_butler.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
@@ -104,10 +103,12 @@ Session::start_butler_thread ()
void
Session::terminate_butler_thread ()
{
- void* status;
- char c = ButlerRequest::Quit;
- ::write (butler_request_pipe[1], &c, 1);
- pthread_join (butler_thread, &status);
+ if (butler_thread) {
+ void* status;
+ char c = ButlerRequest::Quit;
+ ::write (butler_request_pipe[1], &c, 1);
+ pthread_join (butler_thread, &status);
+ }
}
void
diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc
index f09c7232d7..9dccce04f2 100644
--- a/libs/ardour/session_click.cc
+++ b/libs/ardour/session_click.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <list>
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index 7cf52b741f..62067bfb46 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -394,7 +394,7 @@ Session::GlobalMeteringStateCommand::get_state()
if (r) {
child->add_property (X_("id"), r->id().to_s());
- const char* meterstr;
+ const char* meterstr = 0;
switch (x->second) {
case MeterInput:
@@ -406,6 +406,8 @@ Session::GlobalMeteringStateCommand::get_state()
case MeterPostFader:
meterstr = X_("post");
break;
+ default:
+ fatal << string_compose (_("programming error: %1") , "no meter state in Session::GlobalMeteringStateCommand::get_state") << endmsg;
}
child->add_property (X_("meter"), meterstr);
@@ -432,6 +434,7 @@ Session::GlobalMeteringStateCommand::get_state()
case MeterPostFader:
meterstr = X_("post");
break;
+ default: meterstr = "";
}
child->add_property (X_("meter"), meterstr);
diff --git a/libs/ardour/session_control.cc b/libs/ardour/session_control.cc
deleted file mode 100644
index afecc146b7..0000000000
--- a/libs/ardour/session_control.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-
-#include <ardour/session.h>
-#include <control_protocol/control_protocol.h>
-#include <generic_midi/generic_midi_control_protocol.h>
-#include <transport/tranzport_control_protocol.h>
-
-using namespace ARDOUR;
-
-void
-Session::initialize_control ()
-{
- GenericMidiControlProtocol* midi_protocol = new GenericMidiControlProtocol (*this);
-
- if (midi_protocol->init() == 0) {
- control_protocols.push_back (midi_protocol);
- }
-
- if (Config->get_use_tranzport()) {
- cerr << "Creating new tranzport control" << endl;
-
- TranzportControlProtocol* tranzport_protocol = new TranzportControlProtocol (*this);
-
- cerr << "Initializing new tranzport control" << endl;
-
- if (tranzport_protocol->init() == 0) {
- control_protocols.push_back (tranzport_protocol);
- }
- }
-}
-
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index 981f9505d9..35c1019c0e 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc
index 6902a426c3..e2d79b86d3 100644
--- a/libs/ardour/session_export.cc
+++ b/libs/ardour/session_export.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
/* see gdither.cc for why we have to do this */
@@ -269,7 +268,7 @@ AudioExportSpecification::process (nframes_t nframes)
char errbuf[256];
nframes_t to_write = 0;
int cnt = 0;
-
+
do {
/* now do sample rate conversion */
@@ -429,8 +428,6 @@ AudioExportSpecification::process (nframes_t nframes)
int
Session::start_audio_export (AudioExportSpecification& spec)
{
- int ret;
-
if (spec.prepare (current_block_size, frame_rate())) {
return -1;
}
@@ -438,40 +435,21 @@ Session::start_audio_export (AudioExportSpecification& spec)
spec.pos = spec.start_frame;
spec.end_frame = spec.end_frame;
spec.total_frames = spec.end_frame - spec.start_frame;
+ spec.running = true;
+ spec.do_freewheel = false; /* force a call to ::prepare_to_export() before proceeding to normal operation */
spec.freewheel_connection = _engine.Freewheel.connect (sigc::bind (mem_fun (*this, &Session::process_export), &spec));
- if ((ret = _engine.freewheel (true)) == 0) {
- spec.running = true;
- spec.do_freewheel = false;
- }
-
- return ret;
+ return _engine.freewheel (true);
}
int
Session::stop_audio_export (AudioExportSpecification& spec)
{
- /* can't use stop_transport() here because we need
- an immediate halt and don't require all the declick
- stuff that stop_transport() implements.
- */
-
- realtime_stop (true);
- schedule_butler_transport_work ();
-
- /* restart slaving */
+ /* don't stop freewheeling but do stop paying attention to it for now */
- if (post_export_slave != None) {
- Config->set_slave_source (post_export_slave);
- } else {
- locate (post_export_position, false, false, false);
- }
-
- spec.clear ();
- _exporting = false;
-
- spec.running = false;
+ spec.freewheel_connection.disconnect ();
+ spec.clear (); /* resets running/stop etc */
return 0;
}
@@ -645,3 +623,25 @@ Session::process_export (nframes_t nframes, AudioExportSpecification* spec)
return ret;
}
+void
+Session::finalize_audio_export ()
+{
+ _engine.freewheel (false);
+ _exporting = false;
+
+ /* can't use stop_transport() here because we need
+ an immediate halt and don't require all the declick
+ stuff that stop_transport() implements.
+ */
+
+ realtime_stop (true);
+ schedule_butler_transport_work ();
+
+ /* restart slaving */
+
+ if (post_export_slave != None) {
+ Config->set_slave_source (post_export_slave);
+ } else {
+ locate (post_export_position, false, false, false);
+ }
+}
diff --git a/libs/ardour/session_feedback.cc b/libs/ardour/session_feedback.cc
index 1fd8389e11..2bb9886f50 100644
--- a/libs/ardour/session_feedback.cc
+++ b/libs/ardour/session_feedback.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <string>
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index 18bf9b83e1..2a078565b5 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <string>
@@ -90,50 +89,98 @@ int
Session::set_mtc_port (string port_tag)
{
#if 0
- MTC_Slave *ms;
+ MIDI::byte old_device_id = 0;
+ bool reset_id = false;
if (port_tag.length() == 0) {
-
- if (_slave && ((ms = dynamic_cast<MTC_Slave*> (_slave)) != 0)) {
- error << _("Ardour is slaved to MTC - port cannot be reset") << endmsg;
- return -1;
- }
-
- if (_mtc_port == 0) {
+ if (_mmc_port == 0) {
return 0;
}
-
- _mtc_port = 0;
+ _mmc_port = 0;
goto out;
}
MIDI::Port* port;
if ((port = MIDI::Manager::instance()->port (port_tag)) == 0) {
- error << string_compose (_("unknown port %1 requested for MTC"), port_tag) << endl;
return -1;
}
- _mtc_port = port;
+ _mmc_port = port;
- if (_slave && ((ms = dynamic_cast<MTC_Slave*> (_slave)) != 0)) {
- ms->rebind (*port);
+ if (mmc) {
+ old_device_id = mmc->device_id();
+ reset_id = true;
+ delete mmc;
}
- Config->set_mtc_port_name (port_tag);
+ mmc = new MIDI::MachineControl (*_mmc_port, 1.0,
+ MMC_CommandSignature,
+ MMC_ResponseSignature);
+
+ if (reset_id) {
+ mmc->set_device_id (old_device_id);
+ }
+
+ mmc->Play.connect
+ (mem_fun (*this, &Session::mmc_deferred_play));
+ mmc->DeferredPlay.connect
+ (mem_fun (*this, &Session::mmc_deferred_play));
+ mmc->Stop.connect
+ (mem_fun (*this, &Session::mmc_stop));
+ mmc->FastForward.connect
+ (mem_fun (*this, &Session::mmc_fast_forward));
+ mmc->Rewind.connect
+ (mem_fun (*this, &Session::mmc_rewind));
+ mmc->Pause.connect
+ (mem_fun (*this, &Session::mmc_pause));
+ mmc->RecordPause.connect
+ (mem_fun (*this, &Session::mmc_record_pause));
+ mmc->RecordStrobe.connect
+ (mem_fun (*this, &Session::mmc_record_strobe));
+ mmc->RecordExit.connect
+ (mem_fun (*this, &Session::mmc_record_exit));
+ mmc->Locate.connect
+ (mem_fun (*this, &Session::mmc_locate));
+ mmc->Step.connect
+ (mem_fun (*this, &Session::mmc_step));
+ mmc->Shuttle.connect
+ (mem_fun (*this, &Session::mmc_shuttle));
+ mmc->TrackRecordStatusChange.connect
+ (mem_fun (*this, &Session::mmc_record_enable));
+
+
+ /* also handle MIDI SPP because its so common */
+
+ _mmc_port->input()->start.connect (mem_fun (*this, &Session::spp_start));
+ _mmc_port->input()->contineu.connect (mem_fun (*this, &Session::spp_continue));
+ _mmc_port->input()->stop.connect (mem_fun (*this, &Session::spp_stop));
+
+ Config->set_mmc_port_name (port_tag);
out:
- #endif
- MTC_PortChanged(); /* EMIT SIGNAL */
+ MMC_PortChanged(); /* EMIT SIGNAL */
change_midi_ports ();
set_dirty();
+#endif
return 0;
}
+void
+Session::set_mmc_device_id (uint32_t device_id)
+{
+ if (mmc) {
+ mmc->set_device_id (device_id);
+ }
+}
+
int
Session::set_mmc_port (string port_tag)
{
#if 0
+ MIDI::byte old_device_id = 0;
+ bool reset_id = false;
+
if (port_tag.length() == 0) {
if (_mmc_port == 0) {
return 0;
@@ -151,6 +198,8 @@ Session::set_mmc_port (string port_tag)
_mmc_port = port;
if (mmc) {
+ old_device_id = mmc->device_id();
+ reset_id = true;
delete mmc;
}
@@ -158,6 +207,9 @@ Session::set_mmc_port (string port_tag)
MMC_CommandSignature,
MMC_ResponseSignature);
+ if (reset_id) {
+ mmc->set_device_id (old_device_id);
+ }
mmc->Play.connect
(mem_fun (*this, &Session::mmc_deferred_play));
@@ -186,6 +238,7 @@ Session::set_mmc_port (string port_tag)
mmc->TrackRecordStatusChange.connect
(mem_fun (*this, &Session::mmc_record_enable));
+
/* also handle MIDI SPP because its so common */
_mmc_port->input()->start.connect (mem_fun (*this, &Session::spp_start));
@@ -193,6 +246,7 @@ Session::set_mmc_port (string port_tag)
_mmc_port->input()->stop.connect (mem_fun (*this, &Session::spp_stop));
Config->set_mmc_port_name (port_tag);
+
out:
#endif
MMC_PortChanged(); /* EMIT SIGNAL */
@@ -1127,15 +1181,17 @@ Session::start_midi_thread ()
void
Session::terminate_midi_thread ()
{
- MIDIRequest* request = new MIDIRequest;
- void* status;
-
- request->type = MIDIRequest::Quit;
-
- midi_requests.write (&request, 1);
- poke_midi_thread ();
-
- pthread_join (midi_thread, &status);
+ if (midi_thread) {
+ MIDIRequest* request = new MIDIRequest;
+ void* status;
+
+ request->type = MIDIRequest::Quit;
+
+ midi_requests.write (&request, 1);
+ poke_midi_thread ();
+
+ pthread_join (midi_thread, &status);
+ }
}
void
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 2de3448cd1..9b8b7f1d24 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
@@ -306,7 +305,7 @@ Session::process_with_events (nframes_t nframes)
return;
}
- end_frame = _transport_frame + nframes;
+ end_frame = _transport_frame + (nframes_t)abs(floor(nframes * _transport_speed));
{
Event* this_event;
@@ -354,20 +353,15 @@ Session::process_with_events (nframes_t nframes)
while (nframes) {
- if (this_event == 0 || this_event->action_frame > end_frame || this_event->action_frame < _transport_frame) {
+ this_nframes = nframes; /* real (jack) time relative */
+ frames_moved = (long) floor (_transport_speed * nframes); /* transport relative */
- this_nframes = nframes;
-
- } else {
-
- /* compute nframes to next event */
-
- if (this_event->action_frame < end_frame) {
- this_nframes = nframes - (end_frame - this_event->action_frame);
- } else {
- this_nframes = nframes;
- }
- }
+ /* running an event, position transport precisely to its time */
+ if (this_event && this_event->action_frame <= end_frame && this_event->action_frame >= _transport_frame) {
+ /* this isn't quite right for reverse play */
+ frames_moved = (long) (this_event->action_frame - _transport_frame);
+ this_nframes = (nframes_t) abs( floor(frames_moved / _transport_speed) );
+ }
if (this_nframes) {
@@ -386,8 +380,6 @@ Session::process_with_events (nframes_t nframes)
nframes -= this_nframes;
offset += this_nframes;
- frames_moved = (nframes_t) floor (_transport_speed * this_nframes);
-
if (frames_moved < 0) {
decrement_transport_position (-frames_moved);
} else {
@@ -419,8 +411,7 @@ Session::process_with_events (nframes_t nframes)
}
/* this is necessary to handle the case of seamless looping */
- /* not sure if it will work in conjuction with varispeed */
- end_frame = _transport_frame + nframes;
+ end_frame = _transport_frame + (nframes_t) floor (nframes * _transport_speed);
}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index c8a81be4d4..aae5830b34 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS 1
@@ -71,7 +70,8 @@
#include <ardour/midi_playlist.h>
#include <ardour/smf_source.h>
#include <ardour/audiofilesource.h>
-#include <ardour/destructive_filesource.h>
+#include <ardour/silentfilesource.h>
+#include <ardour/sndfilesource.h>
#include <ardour/midi_source.h>
#include <ardour/sndfile_helpers.h>
#include <ardour/auditioner.h>
@@ -193,6 +193,8 @@ Session::first_stage_init (string fullpath, string snapshot_name)
current_trans = 0;
first_file_data_format_reset = true;
first_file_header_format_reset = true;
+ butler_thread = (pthread_t) 0;
+ //midi_thread = (pthread_t) 0;
AudioDiskstream::allocate_working_buffers();
@@ -477,11 +479,16 @@ Session::create (bool& new_session, string* mix_template, nframes_t initial_leng
return -1;
}
- dir = sound_dir ();
+ /* if this is is an existing session with an old "sounds" directory, just use it. see Session::sound_dir() for more details */
- if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
- error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
- return -1;
+ if (!Glib::file_test (old_sound_dir(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
+
+ dir = sound_dir ();
+
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
+ }
}
dir = dead_sound_dir ();
@@ -498,6 +505,13 @@ Session::create (bool& new_session, string* mix_template, nframes_t initial_leng
return -1;
}
+ dir = export_dir ();
+
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session export dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
+ }
+
/* check new_session so we don't overwrite an existing one */
@@ -608,6 +622,12 @@ Session::save_state (string snapshot_name, bool pending)
return 1;
}
+ if (!_engine.connected ()) {
+ error << _("Ardour's audio engine is not connected and state saving would lose all I/O connections. Session not saved")
+ << endmsg;
+ return 1;
+ }
+
tree.set_root (&get_state());
if (snapshot_name.empty()) {
@@ -1442,6 +1462,19 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
try {
boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
+
+ /* a final detail: this is the one and only place that we know how long missing files are */
+
+ if (region->whole_file()) {
+ for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
+ boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
+ if (sfp) {
+ sfp->set_length (region->length());
+ }
+ }
+ }
+
+
return region;
}
@@ -1533,11 +1566,16 @@ Session::path_from_region_name (string name, string identifier)
} else {
snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 ".wav", dir.c_str(), name.c_str(), n);
}
- if (access (buf, F_OK) != 0) {
+
+ if (!g_file_test (buf, G_FILE_TEST_EXISTS)) {
return buf;
}
}
+ error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
+ name, identifier)
+ << endmsg;
+
return "";
}
@@ -1555,10 +1593,16 @@ Session::load_sources (const XMLNode& node)
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
- if ((source = XMLSourceFactory (**niter)) == 0) {
- error << _("Session: cannot create Source from XML description.") << endmsg;
+ try {
+ if ((source = XMLSourceFactory (**niter)) == 0) {
+ error << _("Session: cannot create Source from XML description.") << endmsg;
+ }
}
+ catch (non_existent_source& err) {
+ warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
+ source = SourceFactory::createSilent (*this, **niter, max_frames, _current_frame_rate);
+ }
}
return 0;
@@ -1574,7 +1618,7 @@ Session::XMLSourceFactory (const XMLNode& node)
try {
return SourceFactory::create (*this, node);
}
-
+
catch (failed_constructor& err) {
error << _("Found a sound file that cannot be used by Ardour. Talk to the progammers.") << endmsg;
return boost::shared_ptr<Source>();
@@ -1922,36 +1966,34 @@ Session::dead_sound_dir () const
{
string res = _path;
res += dead_sound_dir_name;
- res += '/';
+
return res;
}
string
-Session::sound_dir (bool with_path) const
+Session::old_sound_dir (bool with_path) const
{
- /* support old session structure */
+ string res;
- struct stat statbuf;
- string old_nopath;
- string old_withpath;
+ if (with_path) {
+ res = _path;
+ }
- old_nopath += old_sound_dir_name;
- old_nopath += '/';
-
- old_withpath = _path;
- old_withpath += old_sound_dir_name;
+ res += old_sound_dir_name;
- if (stat (old_withpath.c_str(), &statbuf) == 0) {
- if (with_path)
- return old_withpath;
-
- return old_nopath;
- }
+ return res;
+}
+string
+Session::sound_dir (bool with_path) const
+{
string res;
+ string full;
if (with_path) {
res = _path;
+ } else {
+ full = _path;
}
res += interchange_dir_name;
@@ -1960,6 +2002,38 @@ Session::sound_dir (bool with_path) const
res += '/';
res += sound_dir_name;
+ if (with_path) {
+ full = res;
+ } else {
+ full += res;
+ }
+
+ /* if this already exists, don't check for the old session sound directory */
+
+ if (Glib::file_test (full, Glib::FILE_TEST_IS_DIR|Glib::FILE_TEST_EXISTS)) {
+ return res;
+ }
+
+ /* possibly support old session structure */
+
+ string old_nopath;
+ string old_withpath;
+
+ old_nopath += old_sound_dir_name;
+ old_nopath += '/';
+
+ old_withpath = _path;
+ old_withpath += old_sound_dir_name;
+
+ if (Glib::file_test (old_withpath.c_str(), Glib::FILE_TEST_IS_DIR|Glib::FILE_TEST_EXISTS)) {
+ if (with_path)
+ return old_withpath;
+
+ return old_nopath;
+ }
+
+ /* ok, old "sounds" directory isn't there, return the new path */
+
return res;
}
@@ -1990,6 +2064,15 @@ Session::template_dir ()
}
string
+Session::export_dir () const
+{
+ string res = _path;
+ res += export_dir_name;
+ res += '/';
+ return res;
+}
+
+string
Session::suffixed_search_path (string suffix, bool data)
{
string path;
@@ -2703,7 +2786,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
on whichever filesystem it was already on.
*/
- if (_path.find ("/sounds/")) {
+ if ((*x).find ("/sounds/") != string::npos) {
/* old school, go up 1 level */
@@ -2898,6 +2981,12 @@ Session::set_deletion_in_progress ()
void
Session::add_controllable (Controllable* c)
{
+ /* this adds a controllable to the list managed by the Session.
+ this is a subset of those managed by the Controllable class
+ itself, and represents the only ones whose state will be saved
+ as part of the session.
+ */
+
Glib::Mutex::Lock lm (controllables_lock);
controllables.insert (c);
}
@@ -3131,6 +3220,12 @@ Session::config_changed (const char* parameter_name)
//poke_midi_thread ();
+ } else if (PARAM_IS ("mmc-device-id")) {
+
+ if (mmc) {
+ mmc->set_device_id (Config->get_mmc_device_id());
+ }
+
} else if (PARAM_IS ("midi-control")) {
//poke_midi_thread ();
@@ -3233,6 +3328,8 @@ Session::config_changed (const char* parameter_name)
} else if (PARAM_IS ("slave-source")) {
set_slave_source (Config->get_slave_source());
+ } else if (PARAM_IS ("remote-model")) {
+ set_remote_control_ids ();
}
set_dirty ();
diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc
index 585dad6b1a..836958f667 100644
--- a/libs/ardour/session_time.cc
+++ b/libs/ardour/session_time.cc
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <iostream>
diff --git a/libs/ardour/session_timefx.cc b/libs/ardour/session_timefx.cc
index 69a42ec8b8..4061b2ccd0 100644
--- a/libs/ardour/session_timefx.cc
+++ b/libs/ardour/session_timefx.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cerrno>
@@ -50,6 +49,9 @@ Session::tempoize_region (TimeStretchRequest& tsr)
float percentage;
nframes_t total_frames;
nframes_t done;
+ int c;
+ char buf[64];
+ string::size_type len;
/* the soundtouch code wants a *tempo* change percentage, which is
of opposite sign to the length change.
@@ -73,8 +75,18 @@ Session::tempoize_region (TimeStretchRequest& tsr)
done = 0;
for (uint32_t i = 0; i < tsr.region->n_channels(); ++i) {
- string path = path_from_region_name (PBD::basename_nosuffix (names[i]), ident);
+ string rstr;
+ string::size_type existing_ident;
+
+ if ((existing_ident = names[i].find (ident)) != string::npos) {
+ rstr = names[i].substr (0, existing_ident);
+ } else {
+ rstr = names[i];
+ }
+
+ string path = path_from_region_name (PBD::basename_nosuffix (rstr), ident);
+
if (path.length() == 0) {
error << string_compose (_("tempoize: error creating name for new audio file based on %1"), tsr.region->name())
<< endmsg;
@@ -88,6 +100,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
error << string_compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
goto out;
}
+
}
try {
@@ -164,7 +177,34 @@ Session::tempoize_region (TimeStretchRequest& tsr)
}
}
- region_name = tsr.region->name() + X_(".t");
+ len = tsr.region->name().length();
+
+ while (--len) {
+ if (!isdigit (tsr.region->name()[len])) {
+ break;
+ }
+ }
+
+ if (len == 0) {
+
+ region_name = tsr.region->name() + ".t000";
+
+ } else {
+
+ if (tsr.region->name()[len] == 't') {
+ c = atoi (tsr.region->name().substr(len+1));
+
+ snprintf (buf, sizeof (buf), "t%03d", ++c);
+ region_name = tsr.region->name().substr (0, len) + buf;
+
+ } else {
+
+ /* not sure what this is, just tack the suffix on to it */
+
+ region_name = tsr.region->name() + ".t000";
+ }
+
+ }
r = (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, 0, sources.front()->length(), region_name,
0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index ad3573a72e..3ee74231e0 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cmath>
@@ -181,7 +180,7 @@ Session::realtime_stop (bool abort)
waiting_for_sync_offset = true;
}
- transport_sub_state = (Config->get_auto_return() ? AutoReturning : 0);
+ transport_sub_state = ((Config->get_slave_source() == None && Config->get_auto_return()) ? AutoReturning : 0);
}
void
@@ -377,13 +376,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
update_latency_compensation (true, abort);
}
- if (Config->get_auto_return() || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
+ if ((Config->get_slave_source() == None && Config->get_auto_return()) || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
if (pending_locate_flush) {
flush_all_redirects ();
}
-
- if ((Config->get_auto_return() || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
+
+ if (((Config->get_slave_source() == None && Config->get_auto_return()) || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
_transport_frame = last_stop_frame;
@@ -663,8 +662,6 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
} else {
- cerr << "butler not requested\n";
-
/* this is functionally what clear_clicks() does but with a tentative lock */
Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
@@ -808,7 +805,7 @@ Session::set_transport_speed (float speed, bool abort)
before the last stop, then we have to do extra work.
*/
- if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f)) {
+ if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_last_transport_speed == 0.0f && speed < 0.0f)) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
}
@@ -939,7 +936,7 @@ Session::post_transport ()
if (post_transport_work & PostTransportLocate) {
- if ((Config->get_auto_play() && !_exporting) || (post_transport_work & PostTransportRoll)) {
+ if (((Config->get_slave_source() == None && Config->get_auto_play()) && !_exporting) || (post_transport_work & PostTransportRoll)) {
start_transport ();
} else {
diff --git a/libs/ardour/session_vst.cc b/libs/ardour/session_vst.cc
index 70bf1a8042..16233feba2 100644
--- a/libs/ardour/session_vst.cc
+++ b/libs/ardour/session_vst.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <stdbool.h>
diff --git a/libs/ardour/silentfilesource.cc b/libs/ardour/silentfilesource.cc
new file mode 100644
index 0000000000..b34944e342
--- /dev/null
+++ b/libs/ardour/silentfilesource.cc
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2007 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 <ardour/silentfilesource.h>
+
+using namespace ARDOUR;
+
+SilentFileSource::SilentFileSource (Session& s, const XMLNode& node, nframes_t len, float sr)
+ : AudioFileSource (s, node, false)
+{
+ _length = len;
+ _sample_rate = sr;
+}
+
+SilentFileSource::~SilentFileSource ()
+{
+}
+
+void
+SilentFileSource::set_length (nframes_t len)
+{
+ _length = len;
+}
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index 2885240a51..d11afa736b 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <cerrno>
@@ -36,6 +35,7 @@
using namespace std;
using namespace ARDOUR;
using namespace PBD;
+using Glib::ustring;
gain_t* SndFileSource::out_coefficient = 0;
gain_t* SndFileSource::in_coefficient = 0;
@@ -50,18 +50,16 @@ SndFileSource::SndFileSource (Session& s, const XMLNode& node)
{
init ();
- cerr << "SndFileSource @ " << _path << " channel = " << channel << endl;
-
if (open()) {
throw failed_constructor ();
}
}
-SndFileSource::SndFileSource (Session& s, string path, int chn, Flag flags)
+SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
/* files created this way are never writable or removable */
: AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
{
- channel = chn;
+ _channel = chn;
init ();
@@ -70,7 +68,7 @@ SndFileSource::SndFileSource (Session& s, string path, int chn, Flag flags)
}
}
-SndFileSource::SndFileSource (Session& s, string path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
+SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
: AudioFileSource (s, path, flags, sfmt, hf)
{
int fmt = 0;
@@ -180,7 +178,7 @@ SndFileSource::SndFileSource (Session& s, string path, SampleFormat sfmt, Header
void
SndFileSource::init ()
{
- string file;
+ ustring file;
// lets try to keep the object initalizations here at the top
xfade_buf = 0;
@@ -224,8 +222,8 @@ SndFileSource::open ()
return -1;
}
- if (channel >= _info.channels) {
- error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg;
+ if (_channel >= _info.channels) {
+ error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
sf_close (sf);
sf = 0;
return -1;
@@ -349,7 +347,7 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
}
nread = sf_read_float (sf, interleave_buf, real_cnt);
- ptr = interleave_buf + channel;
+ ptr = interleave_buf + _channel;
nread /= _info.channels;
/* stride through the interleaved data */
@@ -390,7 +388,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
nframes_t oldlen;
int32_t frame_pos = _length;
-
+
if (write_float (data, frame_pos, cnt) != cnt) {
return 0;
}
@@ -399,28 +397,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
update_length (oldlen, cnt);
if (_build_peakfiles) {
- PeakBuildRecord *pbr = 0;
-
- if (pending_peak_builds.size()) {
- pbr = pending_peak_builds.back();
- }
-
- if (pbr && pbr->frame + pbr->cnt == oldlen) {
-
- /* the last PBR extended to the start of the current write,
- so just extend it again.
- */
- pbr->cnt += cnt;
- } else {
- pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
- }
-
- _peaks_built = false;
- }
-
-
- if (_build_peakfiles) {
- queue_for_peaks (shared_from_this (), false);
+ compute_and_write_peaks (data, frame_pos, cnt, false);
}
_write_data_count = cnt;
@@ -510,32 +487,12 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
old_file_pos = file_pos;
update_length (file_pos, cnt);
- file_pos += cnt;
if (_build_peakfiles) {
- PeakBuildRecord *pbr = 0;
-
- if (pending_peak_builds.size()) {
- pbr = pending_peak_builds.back();
- }
-
- if (pbr && pbr->frame + pbr->cnt == old_file_pos) {
-
- /* the last PBR extended to the start of the current write,
- so just extend it again.
- */
-
- pbr->cnt += cnt;
- } else {
- pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt));
- }
-
- _peaks_built = false;
+ compute_and_write_peaks (data, file_pos, cnt, false);
}
- if (_build_peakfiles) {
- queue_for_peaks (shared_from_this (), true);
- }
+ file_pos += cnt;
return cnt;
}
@@ -630,9 +587,6 @@ SndFileSource::set_header_timeline_position ()
delete _broadcast_info;
_broadcast_info = 0;
}
-
-
-
}
nframes_t
@@ -888,7 +842,7 @@ SndFileSource::set_timeline_position (int64_t pos)
}
int
-SndFileSource::get_soundfile_info (string path, SoundFileInfo& info, string& error_msg)
+SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
{
SNDFILE *sf;
SF_INFO sf_info;
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index db2147493a..c4cf1156cd 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <sys/stat.h>
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 560bf03e7f..143d564809 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -22,9 +22,9 @@
#include <ardour/source_factory.h>
#include <ardour/sndfilesource.h>
-#include <ardour/smf_source.h>
-#include <ardour/destructive_filesource.h>
+#include <ardour/silentfilesource.h>
#include <ardour/configuration.h>
+#include <ardour/smf_source.h>
#ifdef HAVE_COREAUDIO
#include <ardour/coreaudiosource.h>
@@ -52,6 +52,14 @@ SourceFactory::setup_peakfile (boost::shared_ptr<Source> s)
return 0;
}
+boost::shared_ptr<Source>
+SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, float sr)
+{
+ boost::shared_ptr<Source> ret (new SilentFileSource (s, node, nframes, sr));
+ SourceCreated (ret);
+ return ret;
+}
+
#ifdef HAVE_COREAUDIO
boost::shared_ptr<Source>
SourceFactory::create (Session& s, const XMLNode& node)
@@ -74,6 +82,9 @@ SourceFactory::create (Session& s, const XMLNode& node)
}
catch (failed_constructor& err) {
+
+ /* this is allowed to throw */
+
boost::shared_ptr<Source> ret (new SndFileSource (s, node));
if (setup_peakfile (ret)) {
return boost::shared_ptr<Source>();
@@ -87,7 +98,6 @@ SourceFactory::create (Session& s, const XMLNode& node)
boost::shared_ptr<Source> ret (new SMFSource (node));
SourceCreated (ret);
return ret;
-
}
return boost::shared_ptr<Source>();
@@ -98,12 +108,14 @@ SourceFactory::create (Session& s, const XMLNode& node)
boost::shared_ptr<Source>
SourceFactory::create (Session& s, const XMLNode& node)
{
+ /* this is allowed to throw */
+
DataType type = DataType::AUDIO;
const XMLProperty* prop = node.property("type");
if (prop) {
type = DataType(prop->value());
}
-
+
if (type == DataType::AUDIO) {
boost::shared_ptr<Source> ret (new SndFileSource (s, node));
@@ -123,7 +135,7 @@ SourceFactory::create (Session& s, const XMLNode& node)
return ret;
}
-
+
return boost::shared_ptr<Source> ();
}
@@ -160,6 +172,9 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
} else {
+
+ /* this is allowed to throw */
+
boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
if (setup_peakfile (ret)) {
return boost::shared_ptr<Source>();
diff --git a/libs/ardour/sse_functions_xmm.cc b/libs/ardour/sse_functions_xmm.cc
new file mode 100644
index 0000000000..5554462132
--- /dev/null
+++ b/libs/ardour/sse_functions_xmm.cc
@@ -0,0 +1,116 @@
+/*
+ Copyright (C) 2007 Paul sDavis
+ Written by Sampo Savolainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <xmmintrin.h>
+#include <ardour/types.h>
+
+void
+x86_sse_find_peaks(float *buf, nframes_t nframes, float *min, float *max)
+{
+ __m128 current_max, current_min, work;
+
+ // Load max and min values into all four slots of the XMM registers
+ current_min = _mm_set1_ps(*min);
+ current_max = _mm_set1_ps(*max);
+
+ // Work input until "buf" reaches 16 byte alignment
+ while ( ((unsigned long)buf) % 16 != 0 && nframes > 0) {
+
+ // Load the next float into the work buffer
+ work = _mm_set1_ps(*buf);
+
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+
+ buf++;
+ nframes--;
+ }
+
+ // use 64 byte prefetch for quadruple quads
+ while (nframes >= 16) {
+ __builtin_prefetch(buf+64,0,0);
+
+ work = _mm_load_ps(buf);
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+ buf+=4;
+ work = _mm_load_ps(buf);
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+ buf+=4;
+ work = _mm_load_ps(buf);
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+ buf+=4;
+ work = _mm_load_ps(buf);
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+ buf+=4;
+ nframes-=16;
+ }
+
+ // work through aligned buffers
+ while (nframes >= 4) {
+
+ work = _mm_load_ps(buf);
+
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+
+ buf+=4;
+ nframes-=4;
+ }
+
+ // work through the rest < 4 samples
+ while ( nframes > 0) {
+
+ // Load the next float into the work buffer
+ work = _mm_set1_ps(*buf);
+
+ current_min = _mm_min_ps(current_min, work);
+ current_max = _mm_max_ps(current_max, work);
+
+ buf++;
+ nframes--;
+ }
+
+ // Find min & max value in current_max through shuffle tricks
+
+ work = current_min;
+ work = _mm_shuffle_ps(work, work, _MM_SHUFFLE(2, 3, 0, 1));
+ work = _mm_min_ps (work, current_min);
+ current_min = work;
+ work = _mm_shuffle_ps(work, work, _MM_SHUFFLE(1, 0, 3, 2));
+ work = _mm_min_ps (work, current_min);
+
+ _mm_store_ss(min, work);
+
+ work = current_max;
+ work = _mm_shuffle_ps(work, work, _MM_SHUFFLE(2, 3, 0, 1));
+ work = _mm_max_ps (work, current_max);
+ current_max = work;
+ work = _mm_shuffle_ps(work, work, _MM_SHUFFLE(1, 0, 3, 2));
+ work = _mm_max_ps (work, current_max);
+
+ _mm_store_ss(max, work);
+}
+
+
+
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index e86c30dd4d..cd59e93054 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index e0ef8fd0b3..51a0414d0c 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS 1
diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc
index 5d7a303fc6..ed78b0942d 100644
--- a/libs/ardour/vst_plugin.cc
+++ b/libs/ardour/vst_plugin.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
diff --git a/libs/clearlooks/clearlooks_theme_main.c b/libs/clearlooks/clearlooks_theme_main.c
index d30d4dd0b7..5356f915dd 100644
--- a/libs/clearlooks/clearlooks_theme_main.c
+++ b/libs/clearlooks/clearlooks_theme_main.c
@@ -9,7 +9,7 @@ theme_init (GTypeModule *module)
{
clearlooks_rc_style_register_type (module);
clearlooks_style_register_type (module);
- printf("theme_init() called from internal clearlooks engine!\n");
+ printf("theme_init() called from internal clearlooks engine\n");
}
G_MODULE_EXPORT void
diff --git a/libs/fst/fst.h b/libs/fst/fst.h
index 9055eac620..493cb2e572 100644
--- a/libs/fst/fst.h
+++ b/libs/fst/fst.h
@@ -82,6 +82,7 @@ extern "C" {
#endif
extern int fst_init ();
+extern void fst_finish ();
extern FSTHandle* fst_load (const char*);
extern int fst_unload (FSTHandle*);
diff --git a/libs/fst/vstwin.c b/libs/fst/vstwin.c
index 8911ff4a01..55061c2b72 100644
--- a/libs/fst/vstwin.c
+++ b/libs/fst/vstwin.c
@@ -326,9 +326,17 @@ DWORD WINAPI gui_event_loop (LPVOID param)
fst_error ("cannot set timer on dummy window");
}
- while (GetMessageA (&msg, NULL, 0,0)) {
+ while (1) {
+
+ GetMessageA (&msg, NULL, 0,0);
+
+ if (msg.message == WM_SYSTEMERROR) {
+ /* sent when this thread is supposed to exist */
+ break;
+ }
- if( msg.message == WM_KEYDOWN ) debreak();
+ if (msg.message == WM_KEYDOWN) debreak();
+
TranslateMessage( &msg );
DispatchMessageA (&msg);
@@ -336,7 +344,6 @@ DWORD WINAPI gui_event_loop (LPVOID param)
and run idle callbacks
*/
-
if( msg.message == WM_TIMER ) {
pthread_mutex_lock (&plugin_mutex);
again:
@@ -411,6 +418,12 @@ fst_init ()
return 0;
}
+void
+fst_finish ()
+{
+ PostThreadMessageA (gui_thread_id, WM_SYSTEMERROR, 0, 0);
+}
+
int
fst_run_editor (FST* fst)
{
@@ -501,7 +514,9 @@ fst_load (const char *path)
return NULL;
}
- if ((fhandle->main_entry = GetProcAddress (fhandle->dll, "main")) == NULL) {
+ typedef AEffect* (*entryFunctionType)(audioMasterCallback);
+
+ if ((fhandle->main_entry = (entryFunctionType) GetProcAddress (fhandle->dll, "main")) == NULL) {
fst_unload (fhandle);
return NULL;
}
diff --git a/libs/glibmm2/autogen.sh b/libs/glibmm2/autogen.sh
index c58ddd27a2..f2f287d325 100755
--- a/libs/glibmm2/autogen.sh
+++ b/libs/glibmm2/autogen.sh
@@ -1,5 +1,27 @@
#! /bin/sh
+# check all tools first
+
+if /usr/bin/which libtoolize >/dev/null 2>&1 ; then
+ :
+else
+ echo "You do not have libtool installed, which is very sadly required to build part of Ardour"
+ exit 1
+fi
+if /usr/bin/which automake >/dev/null 2>&1 ; then
+ :
+else
+ echo "You do not have automake installed, which is very sadly required to build part of Ardour"
+ exit 1
+fi
+if /usr/bin/which autoconf >/dev/null 2>&1 ; then
+ :
+else
+ echo "You do not have autoconf installed, which is very sadly required to build part of Ardour"
+ exit 1
+fi
+
+
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript
index 9c7511c85d..579ba5dd8e 100644
--- a/libs/gtkmm2ext/SConscript
+++ b/libs/gtkmm2ext/SConscript
@@ -40,6 +40,7 @@ click_box.cc
dndtreeview.cc
fastmeter.cc
focus_entry.cc
+grouped_buttons.cc
gtk_ui.cc
hexentry.cc
idle_adjustment.cc
diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc
index f59d192ff1..c3c15b4281 100644
--- a/libs/gtkmm2ext/barcontroller.cc
+++ b/libs/gtkmm2ext/barcontroller.cc
@@ -267,14 +267,12 @@ BarController::expose (GdkEventExpose* event)
gint w, h;
double fract;
- w = darea.get_width() - 2;
- h = darea.get_height() - 2;
-
fract = ((adjustment.get_value() - adjustment.get_lower()) /
(adjustment.get_upper() - adjustment.get_lower()));
switch (_style) {
case Line:
+ w = darea.get_width() - 1;
h = darea.get_height();
x1 = (gint) floor (w * fract);
x2 = x1;
@@ -304,6 +302,10 @@ BarController::expose (GdkEventExpose* event)
break;
case LeftToRight:
+
+ w = darea.get_width() - 2;
+ h = darea.get_height() - 2;
+
x1 = 0;
x2 = (gint) floor (w * fract);
y1 = 0;
diff --git a/libs/gtkmm2ext/bindable_button.cc b/libs/gtkmm2ext/bindable_button.cc
index 76b89deb02..3c3cad6e46 100644
--- a/libs/gtkmm2ext/bindable_button.cc
+++ b/libs/gtkmm2ext/bindable_button.cc
@@ -42,7 +42,7 @@ BindableToggleButton::BindableToggleButton (MIDI::Controllable *mc)
}
BindableToggleButton::BindableToggleButton(MIDI::Controllable *mc, const string &label)
- : ToggleButton (label),
+ : StatefulButton (label),
prompter (Gtk::WIN_POS_MOUSE, 30000, false),
midi_control (mc),
bind_button (2),
@@ -90,17 +90,6 @@ BindableToggleButton::midi_learn()
}
bool
-BindableToggleButton::on_button_press_event (GdkEventButton *ev)
-{
- if ((ev->state & bind_statemask) && ev->button == bind_button) {
- midi_learn ();
- return true;
- }
-
- return false;
-}
-
-bool
BindableToggleButton::prompter_hiding (GdkEventAny *ev)
{
if (unprompting) {
diff --git a/libs/gtkmm2ext/fastmeter.cc b/libs/gtkmm2ext/fastmeter.cc
index 3c489e08ff..253dad80a2 100644
--- a/libs/gtkmm2ext/fastmeter.cc
+++ b/libs/gtkmm2ext/fastmeter.cc
@@ -57,11 +57,10 @@ FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o)
pixrect.x = 0;
pixrect.y = 0;
-
if (orientation == Vertical) {
- pixbuf = request_vertical_meter(250);
+ pixbuf = request_vertical_meter(dimen, 250);
} else {
- pixbuf = request_horizontal_meter(186);
+ pixbuf = request_horizontal_meter(186, dimen);
}
pixheight = pixbuf->get_height();
@@ -79,14 +78,14 @@ FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o)
request_height= pixrect.height;
}
-Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int length)
+Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int width, int height)
{
- if (length < min_v_pixbuf_size)
- length = min_v_pixbuf_size;
- if (length > max_v_pixbuf_size)
- length = max_v_pixbuf_size;
+ if (height < min_v_pixbuf_size)
+ height = min_v_pixbuf_size;
+ if (height > max_v_pixbuf_size)
+ height = max_v_pixbuf_size;
- int index = length - 1;
+ int index = height - 1;
if (v_pixbuf_cache == 0) {
v_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size);
@@ -97,8 +96,6 @@ Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int length)
return ret;
guint8* data;
- int width = 5;
- int height = length;
data = (guint8*) malloc(width*height * 3);
@@ -155,15 +152,15 @@ Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int length)
return ret;
}
-Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_horizontal_meter(int length)
+Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_horizontal_meter(int width, int height)
{
- if (length < min_h_pixbuf_size)
- length = min_h_pixbuf_size;
- if (length > max_h_pixbuf_size)
- length = max_h_pixbuf_size;
+ if (width < min_h_pixbuf_size)
+ width = min_h_pixbuf_size;
+ if (width > max_h_pixbuf_size)
+ width = max_h_pixbuf_size;
+
+ int index = width - 1;
- int index = length - 1;
-
if (h_pixbuf_cache == 0) {
h_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size);
memset(h_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size);
@@ -173,8 +170,6 @@ Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_horizontal_meter(int length)
return ret;
guint8* data;
- int width = length;
- int height = 5;
data = (guint8*) malloc(width*height * 3);
@@ -253,19 +248,20 @@ void
FastMeter::on_size_request (GtkRequisition* req)
{
if (orientation == Vertical) {
+
req->height = request_height;
-
req->height = max(req->height, min_v_pixbuf_size);
req->height = min(req->height, max_v_pixbuf_size);
- req->width = 5;
- } else {
req->width = request_width;
+ } else {
+
+ req->width = request_width;
req->width = max(req->width, min_h_pixbuf_size);
req->width = min(req->width, max_h_pixbuf_size);
- req->height = 5;
+ req->height = request_height;
}
}
@@ -274,8 +270,9 @@ void
FastMeter::on_size_allocate (Gtk::Allocation &alloc)
{
if (orientation == Vertical) {
- if (alloc.get_width() != 5) {
- alloc.set_width(5);
+
+ if (alloc.get_width() != request_width) {
+ alloc.set_width (request_width);
}
int h = alloc.get_height();
@@ -286,11 +283,13 @@ FastMeter::on_size_allocate (Gtk::Allocation &alloc)
alloc.set_height(h);
if (pixheight != h) {
- pixbuf = request_vertical_meter(h);
+ pixbuf = request_vertical_meter(request_width, h);
}
+
} else {
- if (alloc.get_height() != 5) {
- alloc.set_height(5);
+
+ if (alloc.get_height() != request_height) {
+ alloc.set_height(request_height);
}
int w = alloc.get_width();
@@ -301,7 +300,7 @@ FastMeter::on_size_allocate (Gtk::Allocation &alloc)
alloc.set_width(w);
if (pixwidth != w) {
- pixbuf = request_horizontal_meter(w);
+ pixbuf = request_horizontal_meter(w, request_height);
}
}
diff --git a/libs/gtkmm2ext/grouped_buttons.cc b/libs/gtkmm2ext/grouped_buttons.cc
new file mode 100644
index 0000000000..b16b983d02
--- /dev/null
+++ b/libs/gtkmm2ext/grouped_buttons.cc
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2001 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <gtkmm.h>
+
+#include <gtkmm2ext/grouped_buttons.h>
+
+using namespace std;
+
+GroupedButtons::GroupedButtons (vector<Gtk::ToggleButton *>& buttonset)
+{
+ uint32_t n = 0;
+
+ buttons = buttonset;
+
+ for (vector<Gtk::ToggleButton *>::iterator i = buttons.begin(); i != buttons.end(); ++i, ++n) {
+ if ((*i)->get_active()) {
+ current_active = n;
+ }
+ (*i)->signal_clicked().connect (sigc::bind (mem_fun (*this, &GroupedButtons::one_clicked), n));
+ }
+}
+
+GroupedButtons::GroupedButtons (uint32_t nbuttons, uint32_t first_active)
+{
+ buttons.reserve (nbuttons);
+ current_active = first_active;
+
+ for (uint32_t n = 0; n < nbuttons; ++n) {
+
+ Gtk::ToggleButton *button;
+
+ button = manage (new (Gtk::ToggleButton));
+
+ if (n == current_active) {
+ button->set_active (true);
+ }
+
+ button->signal_clicked().connect (sigc::bind (mem_fun (*this, &GroupedButtons::one_clicked), n));
+ buttons.push_back (button);
+ }
+}
+
+static gint
+reactivate_button (void *arg)
+{
+ Gtk::ToggleButton *b = (Gtk::ToggleButton *) arg;
+ b->set_active (true);
+ return FALSE;
+}
+
+void
+GroupedButtons::one_clicked (uint32_t which)
+{
+ if (buttons[which]->get_active()) {
+
+ if (which != current_active) {
+ uint32_t old = current_active;
+ current_active = which;
+ buttons[old]->set_active (false);
+ }
+
+ } else if (which == current_active) {
+
+ /* Someobody tried to unset the current active
+ button by clicking on it. This caused
+ set_active (false) to be called. We don't
+ allow that, so just reactivate it.
+
+ Don't try this right here, because of some
+ design glitches with GTK+ toggle buttons.
+ Setting the button back to active from
+ within the signal emission that marked
+ it as inactive causes a segfault ...
+ */
+
+ gtk_idle_add (reactivate_button, buttons[which]);
+ }
+}
diff --git a/libs/gtkmm2ext/gtkmm2ext/auto_spin.h b/libs/gtkmm2ext/gtkmm2ext/auto_spin.h
index 68da2249a0..b692a7ccdc 100644
--- a/libs/gtkmm2ext/gtkmm2ext/auto_spin.h
+++ b/libs/gtkmm2ext/gtkmm2ext/auto_spin.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_auto_spin_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
index e5b8e31b58..c91f4c8a06 100644
--- a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
+++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_bar_controller_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h
index 1936125405..2ddd3628fc 100644
--- a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h
+++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __bindable_button_h__
@@ -30,15 +29,46 @@ namespace PBD {
class Controllable;
}
-class BindableToggleButton : public Gtk::ToggleButton
+class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
{
public:
BindableToggleButton (PBD::Controllable& c) : binding_proxy (c) {}
- explicit BindableToggleButton (PBD::Controllable& c, const std::string &label) : Gtk::ToggleButton (label), binding_proxy (c) {}
+
+ explicit BindableToggleButton (PBD::Controllable& c, const std::string &label)
+ : Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {}
+
virtual ~BindableToggleButton() {}
bool on_button_press_event (GdkEventButton *ev) {
- return binding_proxy.button_press_handler (ev);
+ if (!binding_proxy.button_press_handler (ev)) {
+ StatefulToggleButton::on_button_press_event (ev);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private:
+ BindingProxy binding_proxy;
+};
+
+class BindableButton : public Gtkmm2ext::StatefulButton
+{
+ public:
+ BindableButton (PBD::Controllable& c) : binding_proxy (c) {}
+
+ explicit BindableButton (PBD::Controllable& c, const std::string &label)
+ : Gtkmm2ext::StatefulButton (label), binding_proxy (c) {}
+
+ ~BindableButton() {}
+
+ bool on_button_press_event (GdkEventButton *ev) {
+ if (!binding_proxy.button_press_handler (ev)) {
+ StatefulButton::on_button_press_event (ev);
+ return false;
+ } else {
+ return true;
+ }
}
private:
diff --git a/libs/gtkmm2ext/gtkmm2ext/click_box.h b/libs/gtkmm2ext/gtkmm2ext/click_box.h
index e4aee36ebe..8f9fb55717 100644
--- a/libs/gtkmm2ext/gtkmm2ext/click_box.h
+++ b/libs/gtkmm2ext/gtkmm2ext/click_box.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_click_box_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/doi.h b/libs/gtkmm2ext/gtkmm2ext/doi.h
index 16a9a6549c..6ad1f7dd94 100644
--- a/libs/gtkmm2ext/gtkmm2ext/doi.h
+++ b/libs/gtkmm2ext/gtkmm2ext/doi.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_gtk_doi_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/fastmeter.h b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h
index d624f29afb..775cb201cd 100644
--- a/libs/gtkmm2ext/gtkmm2ext/fastmeter.h
+++ b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_fastmeter_h__
@@ -70,13 +69,13 @@ class FastMeter : public Gtk::DrawingArea {
bool vertical_expose (GdkEventExpose*);
bool horizontal_expose (GdkEventExpose*);
- static Glib::RefPtr<Gdk::Pixbuf> request_vertical_meter(int);
+ static Glib::RefPtr<Gdk::Pixbuf> request_vertical_meter(int w, int h);
static Glib::RefPtr<Gdk::Pixbuf> *v_pixbuf_cache;
static int min_v_pixbuf_size;
static int max_v_pixbuf_size;
- static Glib::RefPtr<Gdk::Pixbuf> request_horizontal_meter(int);
+ static Glib::RefPtr<Gdk::Pixbuf> request_horizontal_meter(int w, int h);
static Glib::RefPtr<Gdk::Pixbuf> *h_pixbuf_cache;
static int min_h_pixbuf_size;
diff --git a/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h b/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h
new file mode 100644
index 0000000000..99d9f8ffc4
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/grouped_buttons.h
@@ -0,0 +1,48 @@
+/*
+ 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.
+
+*/
+
+#ifndef __gtkmm2ext_grouped_buttons_h__
+#define __gtkmm2ext_grouped_buttons_h__
+
+#include <stdint.h>
+
+#include <vector>
+#include <sigc++/signal.h>
+
+namespace Gtk {
+ class ToggleButton;
+};
+
+class GroupedButtons : public sigc::trackable
+{
+ public:
+ GroupedButtons (uint32_t nbuttons, uint32_t first_active);
+ GroupedButtons (std::vector<Gtk::ToggleButton *>&);
+
+ Gtk::ToggleButton& button (uint32_t which) {
+ return *buttons[which];
+ }
+
+ private:
+ std::vector<Gtk::ToggleButton *> buttons;
+ uint32_t current_active;
+ void one_clicked (uint32_t which);
+};
+
+#endif /* __gtkmm2ext_grouped_buttons_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
index a692e64c9c..b6a52c6c0c 100644
--- a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
+++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_gtk_ui_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/gtkutils.h b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h
index 1841040560..832423f31d 100644
--- a/libs/gtkmm2ext/gtkmm2ext/gtkutils.h
+++ b/libs/gtkmm2ext/gtkmm2ext/gtkutils.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkutils_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/hexentry.h b/libs/gtkmm2ext/gtkmm2ext/hexentry.h
index 785d6eef36..410f54274e 100644
--- a/libs/gtkmm2ext/gtkmm2ext/hexentry.h
+++ b/libs/gtkmm2ext/gtkmm2ext/hexentry.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_hexentry_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/pixfader.h b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
index bb4176240a..d974f5d5bc 100644
--- a/libs/gtkmm2ext/gtkmm2ext/pixfader.h
+++ b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: fastmeter.h 570 2006-06-07 21:21:21Z sampo $
*/
#ifndef __gtkmm2ext_pixfader_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/popup.h b/libs/gtkmm2ext/gtkmm2ext/popup.h
index 89f14b4c50..1db357341d 100644
--- a/libs/gtkmm2ext/gtkmm2ext/popup.h
+++ b/libs/gtkmm2ext/gtkmm2ext/popup.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __qui_popup_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/prompter.h b/libs/gtkmm2ext/gtkmm2ext/prompter.h
index 9847e73661..10870ee752 100644
--- a/libs/gtkmm2ext/gtkmm2ext/prompter.h
+++ b/libs/gtkmm2ext/gtkmm2ext/prompter.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_prompter_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/selector.h b/libs/gtkmm2ext/gtkmm2ext/selector.h
index 9eb07cfbfe..841742db03 100644
--- a/libs/gtkmm2ext/gtkmm2ext/selector.h
+++ b/libs/gtkmm2ext/gtkmm2ext/selector.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkselector_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
index c137dbabf5..74ff36816b 100644
--- a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
+++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_slider_controller_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/stateful_button.h b/libs/gtkmm2ext/gtkmm2ext/stateful_button.h
index f684903836..c86402e54e 100644
--- a/libs/gtkmm2ext/gtkmm2ext/stateful_button.h
+++ b/libs/gtkmm2ext/gtkmm2ext/stateful_button.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_gtkmm_abutton_h__
@@ -27,28 +26,56 @@
namespace Gtkmm2ext {
-class StatefulButton : public Gtk::Button
+class StateButton
{
public:
- StatefulButton();
- explicit StatefulButton(const std::string &label);
- virtual ~StatefulButton() {}
+ StateButton();
+ virtual ~StateButton() {}
+
+ void set_visual_state (int);
+ int get_visual_state () { return visual_state; }
+ void set_self_managed (bool yn) { _self_managed = yn; }
- void set_colors (const std::vector<Gdk::Color>& colors);
- void set_state (int);
- int get_state () { return current_state; }
- void set_active (bool yn) {
- set_state (yn ? 1 : 0);
- }
-
+ protected:
+ int visual_state;
+ bool _self_managed;
+ bool _is_realized;
+
+ virtual std::string get_widget_name() const = 0;
+ virtual void set_widget_name (std::string) = 0;
+ virtual int get_widget_state() = 0;
+};
+
+
+class StatefulToggleButton : public StateButton, public Gtk::ToggleButton
+{
+ public:
+ StatefulToggleButton() {}
+ explicit StatefulToggleButton(const std::string &label) : Gtk::ToggleButton (label) {}
+ ~StatefulToggleButton() {}
protected:
- std::vector<Gdk::Color> colors;
- int current_state;
- Gdk::Color saved_bg;
- bool have_saved_bg;
+ void on_realize ();
+ void on_toggled ();
+
+ std::string get_widget_name() const { return get_name(); }
+ void set_widget_name (std::string name) { set_name (name); get_child()->set_name (name); }
+ int get_widget_state() { return get_state(); }
+};
+class StatefulButton : public StateButton, public Gtk::Button
+{
+ public:
+ StatefulButton() {}
+ explicit StatefulButton(const std::string &label) : Gtk::Button (label) {}
+ virtual ~StatefulButton() {}
+
+ protected:
void on_realize ();
+
+ std::string get_widget_name() const { return get_name(); }
+ void set_widget_name (std::string name) { set_name (name); get_child()->set_name (name); }
+ int get_widget_state() { return get_state(); }
};
};
diff --git a/libs/gtkmm2ext/gtkmm2ext/tearoff.h b/libs/gtkmm2ext/gtkmm2ext/tearoff.h
index fd36cb6416..5e80892b98 100644
--- a/libs/gtkmm2ext/gtkmm2ext/tearoff.h
+++ b/libs/gtkmm2ext/gtkmm2ext/tearoff.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_tearoff_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/textviewer.h b/libs/gtkmm2ext/gtkmm2ext/textviewer.h
index 280eb4437d..9cc639cd75 100644
--- a/libs/gtkmm2ext/gtkmm2ext/textviewer.h
+++ b/libs/gtkmm2ext/gtkmm2ext/textviewer.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_gtkmm_textviewer_h__
diff --git a/libs/gtkmm2ext/gtkmm2ext/utils.h b/libs/gtkmm2ext/gtkmm2ext/utils.h
index 97dab523aa..ca1b88abba 100644
--- a/libs/gtkmm2ext/gtkmm2ext/utils.h
+++ b/libs/gtkmm2ext/gtkmm2ext/utils.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __gtkmm2ext_utils_h__
diff --git a/libs/gtkmm2ext/stateful_button.cc b/libs/gtkmm2ext/stateful_button.cc
index 074d086651..ffcafab123 100644
--- a/libs/gtkmm2ext/stateful_button.cc
+++ b/libs/gtkmm2ext/stateful_button.cc
@@ -1,31 +1,63 @@
#include <string>
#include <iostream>
-#include "gtkmm2ext/stateful_button.h"
+
+#include <gtkmm/main.h>
+
+#include <gtkmm2ext/stateful_button.h>
using namespace Gtk;
using namespace Glib;
using namespace Gtkmm2ext;
using namespace std;
-StatefulButton::StatefulButton ()
+StateButton::StateButton ()
{
- current_state = 0;
- have_saved_bg = false;
+ _is_realized = false;
+ visual_state = 0;
}
-StatefulButton::StatefulButton (const string& label)
- : Button (label)
+void
+StateButton::set_visual_state (int n)
{
- current_state = 0;
- have_saved_bg = false;
+ if (!_is_realized) {
+ /* not yet realized */
+ visual_state = n;
+ return;
+ }
+
+ if (n == visual_state) {
+ return;
+ }
+
+ string name = get_widget_name ();
+ name = name.substr (0, name.find_last_of ('-'));
+
+ switch (n) {
+ case 0:
+ /* relax */
+ break;
+ case 1:
+ name += "-active";
+ break;
+ case 2:
+ name += "-alternate";
+ break;
+ }
+
+ set_widget_name (name);
+ visual_state = n;
}
+/* ----------------------------------------------------------------- */
+
void
-StatefulButton::set_colors (const vector<Gdk::Color>& c)
+StatefulToggleButton::on_realize ()
{
- colors = c;
- current_state++; // to force transition
- set_state (current_state - 1);
+ ToggleButton::on_realize ();
+
+ _is_realized = true;
+ visual_state++; // to force transition
+ set_visual_state (visual_state - 1);
}
void
@@ -33,48 +65,19 @@ StatefulButton::on_realize ()
{
Button::on_realize ();
- if (!have_saved_bg) {
- saved_bg = get_style()->get_bg (STATE_NORMAL);
- have_saved_bg = true;
- }
-
- current_state++; // to force transition
- set_state (current_state - 1);
+ _is_realized = true;
+ visual_state++; // to force transition
+ set_visual_state (visual_state - 1);
}
void
-StatefulButton::set_state (int n)
+StatefulToggleButton::on_toggled ()
{
- if (is_realized()) {
-
- if (n == current_state) {
- return;
- }
-
- if (n == 0) {
-
- /* back to the default color */
-
- if (have_saved_bg) {
- modify_bg (STATE_NORMAL, saved_bg);
- modify_bg (STATE_ACTIVE, saved_bg);
- modify_bg (STATE_SELECTED, saved_bg);
- modify_bg (STATE_PRELIGHT, saved_bg);
- }
-
-
+ if (!_self_managed) {
+ if (get_active()) {
+ set_visual_state (1);
} else {
-
- int index = (n-1) % colors.size ();
-
- modify_bg (STATE_NORMAL, colors[index]);
- modify_bg (STATE_ACTIVE, colors[index]);
- modify_bg (STATE_SELECTED, colors[index]);
- modify_bg (STATE_PRELIGHT, colors[index]);
+ set_visual_state (0);
}
-
- /* leave insensitive alone */
}
-
- current_state = n;
}
diff --git a/libs/midi++2/macosx/English.lproj/InfoPlist.strings b/libs/midi++2/macosx/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..a7b6345cb0
--- /dev/null
+++ b/libs/midi++2/macosx/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/libs/midi++2/macosx/Info.plist b/libs/midi++2/macosx/Info.plist
new file mode 100644
index 0000000000..8eebfc968f
--- /dev/null
+++ b/libs/midi++2/macosx/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>midi++</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.carbonframeworktemplate</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.01</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/libs/midi++2/macosx/midi++.xcodeproj/project.pbxproj b/libs/midi++2/macosx/midi++.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..49896b11a3
--- /dev/null
+++ b/libs/midi++2/macosx/midi++.xcodeproj/project.pbxproj
@@ -0,0 +1,498 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 696149880B97CED200ECBDF0 /* glib in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149840B97CED200ECBDF0 /* glib */; };
+ 696149890B97CED200ECBDF0 /* gmodule in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149850B97CED200ECBDF0 /* gmodule */; };
+ 6961498A0B97CED200ECBDF0 /* gobject in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149860B97CED200ECBDF0 /* gobject */; };
+ 6961498B0B97CED200ECBDF0 /* gthread in Frameworks */ = {isa = PBXBuildFile; fileRef = 696149870B97CED200ECBDF0 /* gthread */; };
+ 69A0E07A0B8A3B1200A24967 /* coremidi_midiport.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E05C0B8A3B1200A24967 /* coremidi_midiport.cc */; };
+ 69A0E07B0B8A3B1200A24967 /* fd_midiport.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E05D0B8A3B1200A24967 /* fd_midiport.cc */; };
+ 69A0E07C0B8A3B1200A24967 /* fifomidi.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E05E0B8A3B1200A24967 /* fifomidi.cc */; };
+ 69A0E0800B8A3B1200A24967 /* channel.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0630B8A3B1200A24967 /* channel.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0810B8A3B1200A24967 /* coremidi_midiport.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0640B8A3B1200A24967 /* coremidi_midiport.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0820B8A3B1200A24967 /* factory.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0650B8A3B1200A24967 /* factory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0830B8A3B1200A24967 /* fd_midiport.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0660B8A3B1200A24967 /* fd_midiport.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0840B8A3B1200A24967 /* fifomidi.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0670B8A3B1200A24967 /* fifomidi.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0850B8A3B1200A24967 /* manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0680B8A3B1200A24967 /* manager.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0860B8A3B1200A24967 /* mmc.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E0690B8A3B1200A24967 /* mmc.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0870B8A3B1200A24967 /* nullmidi.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E06A0B8A3B1200A24967 /* nullmidi.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0880B8A3B1200A24967 /* parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E06B0B8A3B1200A24967 /* parser.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E0890B8A3B1200A24967 /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E06C0B8A3B1200A24967 /* port.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E08A0B8A3B1200A24967 /* port_request.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E06D0B8A3B1200A24967 /* port_request.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E08B0B8A3B1200A24967 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A0E06E0B8A3B1200A24967 /* types.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69A0E08C0B8A3B1200A24967 /* midi.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E06F0B8A3B1200A24967 /* midi.cc */; };
+ 69A0E08D0B8A3B1200A24967 /* midichannel.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0700B8A3B1200A24967 /* midichannel.cc */; };
+ 69A0E08E0B8A3B1200A24967 /* midifactory.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0710B8A3B1200A24967 /* midifactory.cc */; };
+ 69A0E08F0B8A3B1200A24967 /* midimanager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0720B8A3B1200A24967 /* midimanager.cc */; };
+ 69A0E0900B8A3B1200A24967 /* midiparser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0730B8A3B1200A24967 /* midiparser.cc */; };
+ 69A0E0910B8A3B1200A24967 /* midiport.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0740B8A3B1200A24967 /* midiport.cc */; };
+ 69A0E0930B8A3B1200A24967 /* mmc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0760B8A3B1200A24967 /* mmc.cc */; };
+ 69A0E0950B8A3B1200A24967 /* mtc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0780B8A3B1200A24967 /* mtc.cc */; };
+ 69A0E0960B8A3B1200A24967 /* port_request.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69A0E0790B8A3B1200A24967 /* port_request.cc */; };
+ 69A0E09E0B8A3B6300A24967 /* sigc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69A0E09C0B8A3B6300A24967 /* sigc.framework */; };
+ 69A0E0B00B8A3BEF00A24967 /* CoreMIDI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69A0E0AF0B8A3BEF00A24967 /* CoreMIDI.framework */; };
+ 69A0E0B50B8A3C0B00A24967 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69A0E0B40B8A3C0B00A24967 /* CoreFoundation.framework */; };
+ 69A0E0BA0B8A3C2000A24967 /* glibmm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69A0E0B90B8A3C2000A24967 /* glibmm.framework */; };
+ 69C63C4C0B936ACF00BC0BCA /* version.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69C63C4A0B936ACF00BC0BCA /* version.cc */; };
+ 69C63C4D0B936ACF00BC0BCA /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 69C63C4B0B936ACF00BC0BCA /* version.h */; };
+ 69D5F6010B8D55B100301E71 /* pbd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 69D5F6000B8D55A000301E71 /* pbd.framework */; };
+ 8D07F2BE0486CC7A007CD1D0 /* midi++_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32BAE0B70371A74B00C91783 /* midi++_Prefix.pch */; settings = {ATTRIBUTES = (Public, ); }; };
+ 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 69D5F5FF0B8D55A000301E71 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 69D5F5FB0B8D55A000301E71 /* pbd.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 8D07F2C80486CC7A007CD1D0;
+ remoteInfo = pbd;
+ };
+ 69D5F6060B8D570800301E71 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 69D5F5FB0B8D55A000301E71 /* pbd.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = pbd;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 32BAE0B70371A74B00C91783 /* midi++_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "midi++_Prefix.pch"; sourceTree = "<group>"; };
+ 696149840B97CED200ECBDF0 /* glib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = glib; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/glib; sourceTree = "<absolute>"; };
+ 696149850B97CED200ECBDF0 /* gmodule */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gmodule; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gmodule; sourceTree = "<absolute>"; };
+ 696149860B97CED200ECBDF0 /* gobject */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gobject; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gobject; sourceTree = "<absolute>"; };
+ 696149870B97CED200ECBDF0 /* gthread */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gthread; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gthread; sourceTree = "<absolute>"; };
+ 69A0E05C0B8A3B1200A24967 /* coremidi_midiport.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = coremidi_midiport.cc; path = ../coremidi_midiport.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E05D0B8A3B1200A24967 /* fd_midiport.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = fd_midiport.cc; path = ../fd_midiport.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E05E0B8A3B1200A24967 /* fifomidi.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = fifomidi.cc; path = ../fifomidi.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0630B8A3B1200A24967 /* channel.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = channel.h; sourceTree = "<group>"; };
+ 69A0E0640B8A3B1200A24967 /* coremidi_midiport.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = coremidi_midiport.h; sourceTree = "<group>"; };
+ 69A0E0650B8A3B1200A24967 /* factory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = factory.h; sourceTree = "<group>"; };
+ 69A0E0660B8A3B1200A24967 /* fd_midiport.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fd_midiport.h; sourceTree = "<group>"; };
+ 69A0E0670B8A3B1200A24967 /* fifomidi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fifomidi.h; sourceTree = "<group>"; };
+ 69A0E0680B8A3B1200A24967 /* manager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = manager.h; sourceTree = "<group>"; };
+ 69A0E0690B8A3B1200A24967 /* mmc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mmc.h; sourceTree = "<group>"; };
+ 69A0E06A0B8A3B1200A24967 /* nullmidi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = nullmidi.h; sourceTree = "<group>"; };
+ 69A0E06B0B8A3B1200A24967 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ 69A0E06C0B8A3B1200A24967 /* port.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = port.h; sourceTree = "<group>"; };
+ 69A0E06D0B8A3B1200A24967 /* port_request.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = port_request.h; sourceTree = "<group>"; };
+ 69A0E06E0B8A3B1200A24967 /* types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = "<group>"; };
+ 69A0E06F0B8A3B1200A24967 /* midi.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = midi.cc; path = ../midi.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0700B8A3B1200A24967 /* midichannel.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = midichannel.cc; path = ../midichannel.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0710B8A3B1200A24967 /* midifactory.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = midifactory.cc; path = ../midifactory.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0720B8A3B1200A24967 /* midimanager.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = midimanager.cc; path = ../midimanager.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0730B8A3B1200A24967 /* midiparser.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = midiparser.cc; path = ../midiparser.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0740B8A3B1200A24967 /* midiport.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = midiport.cc; path = ../midiport.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0760B8A3B1200A24967 /* mmc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mmc.cc; path = ../mmc.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0780B8A3B1200A24967 /* mtc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mtc.cc; path = ../mtc.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E0790B8A3B1200A24967 /* port_request.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = port_request.cc; path = ../port_request.cc; sourceTree = SOURCE_ROOT; };
+ 69A0E09C0B8A3B6300A24967 /* sigc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = sigc.framework; path = /Library/Frameworks/sigc.framework; sourceTree = "<absolute>"; };
+ 69A0E0AF0B8A3BEF00A24967 /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = "<absolute>"; };
+ 69A0E0B40B8A3C0B00A24967 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ 69A0E0B90B8A3C2000A24967 /* glibmm.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = glibmm.framework; path = /Library/Frameworks/glibmm.framework; sourceTree = "<absolute>"; };
+ 69C63C4A0B936ACF00BC0BCA /* version.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = version.cc; sourceTree = "<group>"; };
+ 69C63C4B0B936ACF00BC0BCA /* version.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
+ 69D5F5FB0B8D55A000301E71 /* pbd.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = pbd.xcodeproj; path = ../../pbd/macosx/pbd.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ 8D07F2C80486CC7A007CD1D0 /* midi++.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = "midi++.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 69D5F6010B8D55B100301E71 /* pbd.framework in Frameworks */,
+ 69A0E09E0B8A3B6300A24967 /* sigc.framework in Frameworks */,
+ 69A0E0B00B8A3BEF00A24967 /* CoreMIDI.framework in Frameworks */,
+ 69A0E0B50B8A3C0B00A24967 /* CoreFoundation.framework in Frameworks */,
+ 69A0E0BA0B8A3C2000A24967 /* glibmm.framework in Frameworks */,
+ 696149880B97CED200ECBDF0 /* glib in Frameworks */,
+ 696149890B97CED200ECBDF0 /* gmodule in Frameworks */,
+ 6961498A0B97CED200ECBDF0 /* gobject in Frameworks */,
+ 6961498B0B97CED200ECBDF0 /* gthread in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C80486CC7A007CD1D0 /* midi++.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* midi++ */ = {
+ isa = PBXGroup;
+ children = (
+ 69C63C4A0B936ACF00BC0BCA /* version.cc */,
+ 69C63C4B0B936ACF00BC0BCA /* version.h */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 089C1665FE841158C02AAC07 /* Resources */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = "midi++";
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 696149840B97CED200ECBDF0 /* glib */,
+ 696149850B97CED200ECBDF0 /* gmodule */,
+ 696149860B97CED200ECBDF0 /* gobject */,
+ 696149870B97CED200ECBDF0 /* gthread */,
+ 69D5F5FB0B8D55A000301E71 /* pbd.xcodeproj */,
+ 69A0E0B90B8A3C2000A24967 /* glibmm.framework */,
+ 69A0E0B40B8A3C0B00A24967 /* CoreFoundation.framework */,
+ 69A0E0AF0B8A3BEF00A24967 /* CoreMIDI.framework */,
+ 69A0E09C0B8A3B6300A24967 /* sigc.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C1665FE841158C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */,
+ 089C1666FE841158C02AAC07 /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 69A0E05C0B8A3B1200A24967 /* coremidi_midiport.cc */,
+ 69A0E05D0B8A3B1200A24967 /* fd_midiport.cc */,
+ 69A0E05E0B8A3B1200A24967 /* fifomidi.cc */,
+ 69A0E05F0B8A3B1200A24967 /* midi++ */,
+ 69A0E06F0B8A3B1200A24967 /* midi.cc */,
+ 69A0E0700B8A3B1200A24967 /* midichannel.cc */,
+ 69A0E0710B8A3B1200A24967 /* midifactory.cc */,
+ 69A0E0720B8A3B1200A24967 /* midimanager.cc */,
+ 69A0E0730B8A3B1200A24967 /* midiparser.cc */,
+ 69A0E0740B8A3B1200A24967 /* midiport.cc */,
+ 69A0E0760B8A3B1200A24967 /* mmc.cc */,
+ 69A0E0780B8A3B1200A24967 /* mtc.cc */,
+ 69A0E0790B8A3B1200A24967 /* port_request.cc */,
+ 32BAE0B70371A74B00C91783 /* midi++_Prefix.pch */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 69A0E05F0B8A3B1200A24967 /* midi++ */ = {
+ isa = PBXGroup;
+ children = (
+ 69A0E0630B8A3B1200A24967 /* channel.h */,
+ 69A0E0640B8A3B1200A24967 /* coremidi_midiport.h */,
+ 69A0E0650B8A3B1200A24967 /* factory.h */,
+ 69A0E0660B8A3B1200A24967 /* fd_midiport.h */,
+ 69A0E0670B8A3B1200A24967 /* fifomidi.h */,
+ 69A0E0680B8A3B1200A24967 /* manager.h */,
+ 69A0E0690B8A3B1200A24967 /* mmc.h */,
+ 69A0E06A0B8A3B1200A24967 /* nullmidi.h */,
+ 69A0E06B0B8A3B1200A24967 /* parser.h */,
+ 69A0E06C0B8A3B1200A24967 /* port.h */,
+ 69A0E06D0B8A3B1200A24967 /* port_request.h */,
+ 69A0E06E0B8A3B1200A24967 /* types.h */,
+ );
+ name = "midi++";
+ path = "../midi++";
+ sourceTree = SOURCE_ROOT;
+ };
+ 69D5F5FC0B8D55A000301E71 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 69D5F6000B8D55A000301E71 /* pbd.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 69C63C4D0B936ACF00BC0BCA /* version.h in Headers */,
+ 8D07F2BE0486CC7A007CD1D0 /* midi++_Prefix.pch in Headers */,
+ 69A0E0800B8A3B1200A24967 /* channel.h in Headers */,
+ 69A0E0810B8A3B1200A24967 /* coremidi_midiport.h in Headers */,
+ 69A0E0820B8A3B1200A24967 /* factory.h in Headers */,
+ 69A0E0830B8A3B1200A24967 /* fd_midiport.h in Headers */,
+ 69A0E0840B8A3B1200A24967 /* fifomidi.h in Headers */,
+ 69A0E0850B8A3B1200A24967 /* manager.h in Headers */,
+ 69A0E0860B8A3B1200A24967 /* mmc.h in Headers */,
+ 69A0E0870B8A3B1200A24967 /* nullmidi.h in Headers */,
+ 69A0E0880B8A3B1200A24967 /* parser.h in Headers */,
+ 69A0E0890B8A3B1200A24967 /* port.h in Headers */,
+ 69A0E08A0B8A3B1200A24967 /* port_request.h in Headers */,
+ 69A0E08B0B8A3B1200A24967 /* types.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 8D07F2BC0486CC7A007CD1D0 /* midi++ */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "midi++" */;
+ buildPhases = (
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */,
+ 8D07F2C50486CC7A007CD1D0 /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 69D5F6070B8D570800301E71 /* PBXTargetDependency */,
+ );
+ name = "midi++";
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = "midi++";
+ productReference = 8D07F2C80486CC7A007CD1D0 /* midi++.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "midi++" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* midi++ */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 69D5F5FC0B8D55A000301E71 /* Products */;
+ ProjectRef = 69D5F5FB0B8D55A000301E71 /* pbd.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* midi++ */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 69D5F6000B8D55A000301E71 /* pbd.framework */ = {
+ isa = PBXReferenceProxy;
+ fileType = wrapper.framework;
+ path = pbd.framework;
+ remoteRef = 69D5F5FF0B8D55A000301E71 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8D07F2C50486CC7A007CD1D0 /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 69C63C4C0B936ACF00BC0BCA /* version.cc in Sources */,
+ 69A0E07A0B8A3B1200A24967 /* coremidi_midiport.cc in Sources */,
+ 69A0E07B0B8A3B1200A24967 /* fd_midiport.cc in Sources */,
+ 69A0E07C0B8A3B1200A24967 /* fifomidi.cc in Sources */,
+ 69A0E08C0B8A3B1200A24967 /* midi.cc in Sources */,
+ 69A0E08D0B8A3B1200A24967 /* midichannel.cc in Sources */,
+ 69A0E08E0B8A3B1200A24967 /* midifactory.cc in Sources */,
+ 69A0E08F0B8A3B1200A24967 /* midimanager.cc in Sources */,
+ 69A0E0900B8A3B1200A24967 /* midiparser.cc in Sources */,
+ 69A0E0910B8A3B1200A24967 /* midiport.cc in Sources */,
+ 69A0E0930B8A3B1200A24967 /* mmc.cc in Sources */,
+ 69A0E0950B8A3B1200A24967 /* mtc.cc in Sources */,
+ 69A0E0960B8A3B1200A24967 /* port_request.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 69D5F6070B8D570800301E71 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = pbd;
+ targetProxy = 69D5F6060B8D570800301E71 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 089C1667FE841158C02AAC07 /* English */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "midi++_Prefix.pch";
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ PRODUCT_NAME = "midi++";
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Release;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ "$(NATIVE_ARCH)",
+ ppc,
+ );
+ DEAD_CODE_STRIPPING = YES;
+ FRAMEWORK_SEARCH_PATHS = /opt/ardour/build;
+ GCC_FAST_OBJC_DISPATCH = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G4;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ /Library/Frameworks/GLib.framework/Headers,
+ /Library/Frameworks/sigc.framework/Headers,
+ );
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+ 694E7C660B97AD230018D03D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ FRAMEWORK_SEARCH_PATHS = /opt/ardour/build;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_FAST_OBJC_DISPATCH = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ /Library/Frameworks/GLib.framework/Headers,
+ /Library/Frameworks/sigc.framework/Headers,
+ );
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ STRIP_INSTALLED_PRODUCT = NO;
+ };
+ name = Debug;
+ };
+ 694E7C670B97AD230018D03D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = i386;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "midi++_Prefix.pch";
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ PRODUCT_NAME = "midi++";
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "midi++" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24408B4156D00ABE55E /* Release */,
+ 694E7C670B97AD230018D03D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "midi++" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24808B4156D00ABE55E /* Release */,
+ 694E7C660B97AD230018D03D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/libs/midi++2/macosx/midi++_Prefix.pch b/libs/midi++2/macosx/midi++_Prefix.pch
new file mode 100644
index 0000000000..8f1f98260c
--- /dev/null
+++ b/libs/midi++2/macosx/midi++_Prefix.pch
@@ -0,0 +1,3 @@
+//
+// Prefix header for all source files of the 'midi++' target in the 'midi++' project.
+//
diff --git a/libs/midi++2/macosx/version.cc b/libs/midi++2/macosx/version.cc
new file mode 100644
index 0000000000..72e767bca5
--- /dev/null
+++ b/libs/midi++2/macosx/version.cc
@@ -0,0 +1,3 @@
+int midipp_major_version = 2;
+int midipp_minor_version = 1;
+int midipp_micro_version = 1;
diff --git a/libs/midi++2/macosx/version.h b/libs/midi++2/macosx/version.h
new file mode 100644
index 0000000000..7ff7d8ce10
--- /dev/null
+++ b/libs/midi++2/macosx/version.h
@@ -0,0 +1,7 @@
+#ifndef __midipp_version_h__
+#define __midipp_version_h__
+extern const char* midipp_revision;
+extern int midipp_major_version;
+extern int midipp_minor_version;
+extern int midipp_micro_version;
+#endif /* __midipp_version_h__ */
diff --git a/libs/midi++2/midi++/alsa_rawmidi.h b/libs/midi++2/midi++/alsa_rawmidi.h
index f6c17541c2..8e50609fbe 100644
--- a/libs/midi++2/midi++/alsa_rawmidi.h
+++ b/libs/midi++2/midi++/alsa_rawmidi.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __alsa_rawmidi_h__
diff --git a/libs/midi++2/midi++/alsa_sequencer.h b/libs/midi++2/midi++/alsa_sequencer.h
index a4b4ba856f..7fe880fe63 100644
--- a/libs/midi++2/midi++/alsa_sequencer.h
+++ b/libs/midi++2/midi++/alsa_sequencer.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __alsa_sequencer_midiport_h__
diff --git a/libs/midi++2/midi++/channel.h b/libs/midi++2/midi++/channel.h
index e1ffb954a5..5a4a397b9d 100644
--- a/libs/midi++2/midi++/channel.h
+++ b/libs/midi++2/midi++/channel.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __midichannel_h__
diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h
index 1d5c7e0b30..df7f35e073 100644
--- a/libs/midi++2/midi++/factory.h
+++ b/libs/midi++2/midi++/factory.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __midi_factory_h__
diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h
index 3ff05b21c8..8a1af55967 100644
--- a/libs/midi++2/midi++/fd_midiport.h
+++ b/libs/midi++2/midi++/fd_midiport.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __fd_midiport_h__
diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h
index 200d90eda8..57d1502c45 100644
--- a/libs/midi++2/midi++/fifomidi.h
+++ b/libs/midi++2/midi++/fifomidi.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __fifomidi_h__
diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h
index d5a49eb0a3..80de408ee1 100644
--- a/libs/midi++2/midi++/manager.h
+++ b/libs/midi++2/midi++/manager.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __midi_manager_h__
diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h
index 2d569f122c..bc23beb0a1 100644
--- a/libs/midi++2/midi++/mmc.h
+++ b/libs/midi++2/midi++/mmc.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __midipp_mmc_h_h__
@@ -93,6 +92,8 @@ class MachineControl : public sigc::trackable
Port &port() { return _port; }
void set_device_id (byte id);
+ byte device_id () const { return _device_id; }
+
static bool is_mmc (byte *sysex_buf, size_t len);
/* Signals to connect to if you want to run "callbacks"
diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h
index 75445facb7..1474da77ed 100644
--- a/libs/midi++2/midi++/nullmidi.h
+++ b/libs/midi++2/midi++/nullmidi.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __nullmidi_h__
diff --git a/libs/midi++2/midi++/parser.h b/libs/midi++2/midi++/parser.h
index 36d19f3da9..73c7c75f61 100644
--- a/libs/midi++2/midi++/parser.h
+++ b/libs/midi++2/midi++/parser.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __midi_parse_h__
@@ -162,8 +161,8 @@ class Parser : public sigc::trackable {
bool _mmc_forward;
bool _mtc_forward;
int expected_mtc_quarter_frame_code;
- byte _mtc_time[4];
- byte _qtr_mtc_time[4];
+ byte _mtc_time[5];
+ byte _qtr_mtc_time[5];
unsigned long consecutive_qtr_frame_cnt;
MTC_FPS _mtc_fps;
MTC_Status _mtc_running;
diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h
index a706127eff..e4338cf952 100644
--- a/libs/midi++2/midi++/port.h
+++ b/libs/midi++2/midi++/port.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __libmidi_port_h__
diff --git a/libs/midi++2/midi++/port_request.h b/libs/midi++2/midi++/port_request.h
index 86838dd04d..0cb4ffded6 100644
--- a/libs/midi++2/midi++/port_request.h
+++ b/libs/midi++2/midi++/port_request.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __midi_port_request_h__
diff --git a/libs/midi++2/midiparser.cc b/libs/midi++2/midiparser.cc
index 7c29478413..a1f6ce39b4 100644
--- a/libs/midi++2/midiparser.cc
+++ b/libs/midi++2/midiparser.cc
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <string>
#include <iostream>
+#include <iterator>
#include <midi++/types.h>
#include <midi++/parser.h>
@@ -138,7 +139,6 @@ Parser::~Parser ()
void
Parser::trace_event (Parser &p, byte *msg, size_t len)
-
{
eventType type;
ostream *o;
@@ -309,15 +309,13 @@ Parser::trace_event (Parser &p, byte *msg, size_t len)
void
Parser::trace (bool onoff, ostream *o, const string &prefix)
-
{
trace_connection.disconnect ();
if (onoff) {
trace_stream = o;
trace_prefix = prefix;
- trace_connection = any.connect
- (mem_fun (*this, &Parser::trace_event));
+ trace_connection = any.connect (mem_fun (*this, &Parser::trace_event));
} else {
trace_prefix = "";
trace_stream = 0;
diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc
index 61c47e856f..28d6393fb4 100644
--- a/libs/midi++2/mmc.cc
+++ b/libs/midi++2/mmc.cc
@@ -202,7 +202,7 @@ MachineControl::MachineControl (Port &p, float version,
build_mmc_cmd_map ();
- _device_id = 1;
+ _device_id = 0;
if ((parser = _port.input()) != 0) {
parser->mmc.connect
@@ -258,7 +258,7 @@ MachineControl::process_mmc_message (Parser &p, byte *msg, size_t len)
*/
#if 0
- cerr << "*** MMC message: len = " << len << "\n\t";
+ cerr << "*** me = " << (int) _device_id << " MMC message: len = " << len << "\n\t";
for (size_t i = 0; i < len; i++) {
cerr << hex << (int) msg[i] << dec << ' ';
}
diff --git a/libs/midi++2/mtc.cc b/libs/midi++2/mtc.cc
index 19fdb1fabd..7fd86eff35 100644
--- a/libs/midi++2/mtc.cc
+++ b/libs/midi++2/mtc.cc
@@ -36,7 +36,7 @@ using namespace MIDI;
bool
Parser::possible_mtc (byte *sysex_buf, size_t msglen)
{
- byte fake_mtc_time[4];
+ byte fake_mtc_time[5];
if (msglen != 10 || sysex_buf[0] != 0xf0 || sysex_buf[1] != 0x7f || sysex_buf[3] != 0x01 || sysex_buf[4] != 0x01) {
return false;
@@ -50,7 +50,9 @@ Parser::possible_mtc (byte *sysex_buf, size_t msglen)
fake_mtc_time[3] = (sysex_buf[5] & 0x1f); // hours
_mtc_fps = MTC_FPS ((sysex_buf[5] & 0x60) >> 5); // fps
-
+
+ fake_mtc_time[4] = (byte) _mtc_fps;
+
/* wait for first quarter frame, which could indicate forwards
or backwards ...
*/
@@ -262,6 +264,7 @@ Parser::process_mtc_quarter_frame (byte *msg)
_qtr_mtc_time[3] |= ((msg[1] & 0x1) << 4);
_mtc_fps = MTC_FPS ((msg[1] & 0x6) >> 1);
+ _qtr_mtc_time[4] = _mtc_fps;
break;
default:
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
index afb24a4311..12664a1fca 100644
--- a/libs/pbd/SConscript
+++ b/libs/pbd/SConscript
@@ -36,6 +36,7 @@ pthread_utils.cc
receiver.cc
stacktrace.cc
stateful.cc
+strreplace.cc
strsplit.cc
textreceiver.cc
transmitter.cc
diff --git a/libs/pbd/controllable.cc b/libs/pbd/controllable.cc
index 049ad0aa21..00638e6c06 100644
--- a/libs/pbd/controllable.cc
+++ b/libs/pbd/controllable.cc
@@ -10,9 +10,64 @@ sigc::signal<void,Controllable*> Controllable::Destroyed;
sigc::signal<bool,Controllable*> Controllable::StartLearning;
sigc::signal<void,Controllable*> Controllable::StopLearning;
+Glib::Mutex* Controllable::registry_lock = 0;
+Controllable::Controllables Controllable::registry;
+
Controllable::Controllable (std::string name)
: _name (name)
{
+ if (registry_lock == 0) {
+ registry_lock = new Glib::Mutex;
+ }
+
+ add ();
+}
+
+void
+Controllable::add ()
+{
+ Glib::Mutex::Lock lm (*registry_lock);
+ registry.insert (this);
+ this->GoingAway.connect (mem_fun (this, &Controllable::remove));
+}
+
+void
+Controllable::remove ()
+{
+ Glib::Mutex::Lock lm (*registry_lock);
+ for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
+ if ((*i) == this) {
+ registry.erase (i);
+ break;
+ }
+ }
+}
+
+Controllable*
+Controllable::by_id (const ID& id)
+{
+ Glib::Mutex::Lock lm (*registry_lock);
+
+ for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
+ if ((*i)->id() == id) {
+ return (*i);
+ }
+ }
+ return 0;
+}
+
+
+Controllable*
+Controllable::by_name (const std::string& str)
+{
+ Glib::Mutex::Lock lm (*registry_lock);
+
+ for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
+ if ((*i)->_name == str) {
+ return (*i);
+ }
+ }
+ return 0;
}
XMLNode&
diff --git a/libs/pbd/macosx/English.lproj/InfoPlist.strings b/libs/pbd/macosx/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..d8479018a9
--- /dev/null
+++ b/libs/pbd/macosx/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/libs/pbd/macosx/Info.plist b/libs/pbd/macosx/Info.plist
new file mode 100644
index 0000000000..0c31617fd2
--- /dev/null
+++ b/libs/pbd/macosx/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>pbd</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.carbonframeworktemplate</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.01</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/libs/pbd/macosx/pbd.xcodeproj/project.pbxproj b/libs/pbd/macosx/pbd.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..535d16b8a2
--- /dev/null
+++ b/libs/pbd/macosx/pbd.xcodeproj/project.pbxproj
@@ -0,0 +1,634 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 6941206F0B8A34AB00AF661E /* base_ui.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120270B8A34AB00AF661E /* base_ui.cc */; };
+ 694120700B8A34AB00AF661E /* basename.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120280B8A34AB00AF661E /* basename.cc */; };
+ 694120710B8A34AB00AF661E /* command.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120290B8A34AB00AF661E /* command.cc */; };
+ 694120720B8A34AB00AF661E /* controllable.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941202A0B8A34AB00AF661E /* controllable.cc */; };
+ 694120730B8A34AB00AF661E /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941202B0B8A34AB00AF661E /* convert.cc */; };
+ 694120740B8A34AB00AF661E /* copyfile.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941202C0B8A34AB00AF661E /* copyfile.cc */; };
+ 694120750B8A34AB00AF661E /* dmalloc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941202D0B8A34AB00AF661E /* dmalloc.cc */; };
+ 694120760B8A34AB00AF661E /* enumwriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941202E0B8A34AB00AF661E /* enumwriter.cc */; };
+ 694120770B8A34AB00AF661E /* error.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941202F0B8A34AB00AF661E /* error.cc */; };
+ 694120780B8A34AB00AF661E /* gettext.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120300B8A34AB00AF661E /* gettext.h */; settings = {ATTRIBUTES = (); }; };
+ 694120790B8A34AB00AF661E /* i18n.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120310B8A34AB00AF661E /* i18n.h */; settings = {ATTRIBUTES = (); }; };
+ 6941207A0B8A34AB00AF661E /* id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120320B8A34AB00AF661E /* id.cc */; };
+ 6941207B0B8A34AB00AF661E /* mountpoint.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120330B8A34AB00AF661E /* mountpoint.cc */; };
+ 6941207C0B8A34AB00AF661E /* path.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120340B8A34AB00AF661E /* path.cc */; };
+ 6941207D0B8A34AB00AF661E /* pathscanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120350B8A34AB00AF661E /* pathscanner.cc */; };
+ 6941207F0B8A34AB00AF661E /* abstract_ui.cc in Headers */ = {isa = PBXBuildFile; fileRef = 694120380B8A34AB00AF661E /* abstract_ui.cc */; };
+ 694120800B8A34AB00AF661E /* abstract_ui.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120390B8A34AB00AF661E /* abstract_ui.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120810B8A34AB00AF661E /* base_ui.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941203A0B8A34AB00AF661E /* base_ui.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120820B8A34AB00AF661E /* basename.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941203B0B8A34AB00AF661E /* basename.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120830B8A34AB00AF661E /* command.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941203C0B8A34AB00AF661E /* command.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120840B8A34AB00AF661E /* compose.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941203D0B8A34AB00AF661E /* compose.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120850B8A34AB00AF661E /* controllable.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941203E0B8A34AB00AF661E /* controllable.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120860B8A34AB00AF661E /* convert.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941203F0B8A34AB00AF661E /* convert.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120870B8A34AB00AF661E /* copyfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120400B8A34AB00AF661E /* copyfile.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120880B8A34AB00AF661E /* crossthread.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120410B8A34AB00AF661E /* crossthread.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120890B8A34AB00AF661E /* destructible.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120420B8A34AB00AF661E /* destructible.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941208A0B8A34AB00AF661E /* enumwriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120430B8A34AB00AF661E /* enumwriter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941208B0B8A34AB00AF661E /* error.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120440B8A34AB00AF661E /* error.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941208C0B8A34AB00AF661E /* failed_constructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120450B8A34AB00AF661E /* failed_constructor.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941208D0B8A34AB00AF661E /* fastlog.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120460B8A34AB00AF661E /* fastlog.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941208E0B8A34AB00AF661E /* forkexec.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120470B8A34AB00AF661E /* forkexec.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941208F0B8A34AB00AF661E /* id.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120480B8A34AB00AF661E /* id.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120900B8A34AB00AF661E /* mathfix.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120490B8A34AB00AF661E /* mathfix.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120910B8A34AB00AF661E /* memento_command.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941204A0B8A34AB00AF661E /* memento_command.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120920B8A34AB00AF661E /* mountpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941204B0B8A34AB00AF661E /* mountpoint.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120930B8A34AB00AF661E /* path.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941204C0B8A34AB00AF661E /* path.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120940B8A34AB00AF661E /* pathscanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941204D0B8A34AB00AF661E /* pathscanner.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120950B8A34AB00AF661E /* pool.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941204E0B8A34AB00AF661E /* pool.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120960B8A34AB00AF661E /* pthread_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941204F0B8A34AB00AF661E /* pthread_utils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120970B8A34AB00AF661E /* rcu.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120500B8A34AB00AF661E /* rcu.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120980B8A34AB00AF661E /* receiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120510B8A34AB00AF661E /* receiver.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120990B8A34AB00AF661E /* ringbuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120520B8A34AB00AF661E /* ringbuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941209A0B8A34AB00AF661E /* ringbufferNPT.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120530B8A34AB00AF661E /* ringbufferNPT.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941209B0B8A34AB00AF661E /* selectable.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120540B8A34AB00AF661E /* selectable.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941209C0B8A34AB00AF661E /* shiva.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120550B8A34AB00AF661E /* shiva.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941209D0B8A34AB00AF661E /* stacktrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120560B8A34AB00AF661E /* stacktrace.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941209E0B8A34AB00AF661E /* stateful.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120570B8A34AB00AF661E /* stateful.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 6941209F0B8A34AB00AF661E /* statefuldestructible.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120580B8A34AB00AF661E /* statefuldestructible.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A00B8A34AB00AF661E /* stl_delete.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120590B8A34AB00AF661E /* stl_delete.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A10B8A34AB00AF661E /* stl_functors.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941205A0B8A34AB00AF661E /* stl_functors.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A20B8A34AB00AF661E /* strsplit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941205B0B8A34AB00AF661E /* strsplit.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A30B8A34AB00AF661E /* textreceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941205C0B8A34AB00AF661E /* textreceiver.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A40B8A34AB00AF661E /* thrown_error.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941205D0B8A34AB00AF661E /* thrown_error.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A50B8A34AB00AF661E /* tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941205E0B8A34AB00AF661E /* tokenizer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A60B8A34AB00AF661E /* touchable.h in Headers */ = {isa = PBXBuildFile; fileRef = 6941205F0B8A34AB00AF661E /* touchable.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A70B8A34AB00AF661E /* transmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120600B8A34AB00AF661E /* transmitter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A80B8A34AB00AF661E /* undo.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120610B8A34AB00AF661E /* undo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120A90B8A34AB00AF661E /* whitespace.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120620B8A34AB00AF661E /* whitespace.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120AA0B8A34AB00AF661E /* xml++.h in Headers */ = {isa = PBXBuildFile; fileRef = 694120630B8A34AB00AF661E /* xml++.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 694120AB0B8A34AB00AF661E /* pool.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120640B8A34AB00AF661E /* pool.cc */; };
+ 694120AC0B8A34AB00AF661E /* pthread_utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120650B8A34AB00AF661E /* pthread_utils.cc */; };
+ 694120AD0B8A34AB00AF661E /* receiver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120660B8A34AB00AF661E /* receiver.cc */; };
+ 694120AE0B8A34AB00AF661E /* stacktrace.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120670B8A34AB00AF661E /* stacktrace.cc */; };
+ 694120AF0B8A34AB00AF661E /* stateful.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120680B8A34AB00AF661E /* stateful.cc */; };
+ 694120B00B8A34AB00AF661E /* strsplit.cc in Sources */ = {isa = PBXBuildFile; fileRef = 694120690B8A34AB00AF661E /* strsplit.cc */; };
+ 694120B10B8A34AB00AF661E /* textreceiver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941206A0B8A34AB00AF661E /* textreceiver.cc */; };
+ 694120B20B8A34AB00AF661E /* transmitter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941206B0B8A34AB00AF661E /* transmitter.cc */; };
+ 694120B30B8A34AB00AF661E /* undo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941206C0B8A34AB00AF661E /* undo.cc */; };
+ 694120B40B8A34AB00AF661E /* whitespace.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941206D0B8A34AB00AF661E /* whitespace.cc */; };
+ 694120B50B8A34AB00AF661E /* xml++.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6941206E0B8A34AB00AF661E /* xml++.cc */; };
+ 694120D40B8A36A200AF661E /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 694120D30B8A36A200AF661E /* libxml2.dylib */; };
+ 694191980B97CD950083505E /* glibmm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 694191950B97CD950083505E /* glibmm.framework */; };
+ 694191990B97CD950083505E /* sigc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 694191960B97CD950083505E /* sigc.framework */; };
+ 69C63C150B9369CB00BC0BCA /* strreplace.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69C63C140B9369CB00BC0BCA /* strreplace.cc */; };
+ 69C63C190B9369DE00BC0BCA /* replace_all.h in Headers */ = {isa = PBXBuildFile; fileRef = 69C63C180B9369DE00BC0BCA /* replace_all.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69C63C2B0B936A6E00BC0BCA /* version.cc in Sources */ = {isa = PBXBuildFile; fileRef = 69C63C290B936A6E00BC0BCA /* version.cc */; };
+ 69C63C2C0B936A6E00BC0BCA /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = 69C63C2A0B936A6E00BC0BCA /* version.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 69CD7FED0B97CDD50049ED98 /* glib in Frameworks */ = {isa = PBXBuildFile; fileRef = 69CD7FE90B97CDD50049ED98 /* glib */; };
+ 69CD7FEE0B97CDD50049ED98 /* gmodule in Frameworks */ = {isa = PBXBuildFile; fileRef = 69CD7FEA0B97CDD50049ED98 /* gmodule */; };
+ 69CD7FEF0B97CDD50049ED98 /* gobject in Frameworks */ = {isa = PBXBuildFile; fileRef = 69CD7FEB0B97CDD50049ED98 /* gobject */; };
+ 69CD7FF00B97CDD50049ED98 /* gthread in Frameworks */ = {isa = PBXBuildFile; fileRef = 69CD7FEC0B97CDD50049ED98 /* gthread */; };
+ 8D07F2BE0486CC7A007CD1D0 /* pbd_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32BAE0B70371A74B00C91783 /* pbd_Prefix.pch */; settings = {ATTRIBUTES = (); }; };
+ 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 32BAE0B70371A74B00C91783 /* pbd_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pbd_Prefix.pch; sourceTree = "<group>"; };
+ 694120270B8A34AB00AF661E /* base_ui.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = base_ui.cc; path = ../base_ui.cc; sourceTree = SOURCE_ROOT; };
+ 694120280B8A34AB00AF661E /* basename.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basename.cc; path = ../basename.cc; sourceTree = SOURCE_ROOT; };
+ 694120290B8A34AB00AF661E /* command.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = command.cc; path = ../command.cc; sourceTree = SOURCE_ROOT; };
+ 6941202A0B8A34AB00AF661E /* controllable.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = controllable.cc; path = ../controllable.cc; sourceTree = SOURCE_ROOT; };
+ 6941202B0B8A34AB00AF661E /* convert.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = convert.cc; path = ../convert.cc; sourceTree = SOURCE_ROOT; };
+ 6941202C0B8A34AB00AF661E /* copyfile.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = copyfile.cc; path = ../copyfile.cc; sourceTree = SOURCE_ROOT; };
+ 6941202D0B8A34AB00AF661E /* dmalloc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dmalloc.cc; path = ../dmalloc.cc; sourceTree = SOURCE_ROOT; };
+ 6941202E0B8A34AB00AF661E /* enumwriter.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = enumwriter.cc; path = ../enumwriter.cc; sourceTree = SOURCE_ROOT; };
+ 6941202F0B8A34AB00AF661E /* error.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = error.cc; path = ../error.cc; sourceTree = SOURCE_ROOT; };
+ 694120300B8A34AB00AF661E /* gettext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = gettext.h; path = ../gettext.h; sourceTree = SOURCE_ROOT; };
+ 694120310B8A34AB00AF661E /* i18n.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = i18n.h; path = ../i18n.h; sourceTree = SOURCE_ROOT; };
+ 694120320B8A34AB00AF661E /* id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = id.cc; path = ../id.cc; sourceTree = SOURCE_ROOT; };
+ 694120330B8A34AB00AF661E /* mountpoint.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mountpoint.cc; path = ../mountpoint.cc; sourceTree = SOURCE_ROOT; };
+ 694120340B8A34AB00AF661E /* path.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = path.cc; path = ../path.cc; sourceTree = SOURCE_ROOT; };
+ 694120350B8A34AB00AF661E /* pathscanner.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathscanner.cc; path = ../pathscanner.cc; sourceTree = SOURCE_ROOT; };
+ 694120380B8A34AB00AF661E /* abstract_ui.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = abstract_ui.cc; sourceTree = "<group>"; };
+ 694120390B8A34AB00AF661E /* abstract_ui.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = abstract_ui.h; sourceTree = "<group>"; };
+ 6941203A0B8A34AB00AF661E /* base_ui.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = base_ui.h; sourceTree = "<group>"; };
+ 6941203B0B8A34AB00AF661E /* basename.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basename.h; sourceTree = "<group>"; };
+ 6941203C0B8A34AB00AF661E /* command.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = command.h; sourceTree = "<group>"; };
+ 6941203D0B8A34AB00AF661E /* compose.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = compose.h; sourceTree = "<group>"; };
+ 6941203E0B8A34AB00AF661E /* controllable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = controllable.h; sourceTree = "<group>"; };
+ 6941203F0B8A34AB00AF661E /* convert.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = convert.h; sourceTree = "<group>"; };
+ 694120400B8A34AB00AF661E /* copyfile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = copyfile.h; sourceTree = "<group>"; };
+ 694120410B8A34AB00AF661E /* crossthread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = crossthread.h; sourceTree = "<group>"; };
+ 694120420B8A34AB00AF661E /* destructible.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = destructible.h; sourceTree = "<group>"; };
+ 694120430B8A34AB00AF661E /* enumwriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = enumwriter.h; sourceTree = "<group>"; };
+ 694120440B8A34AB00AF661E /* error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = "<group>"; };
+ 694120450B8A34AB00AF661E /* failed_constructor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = failed_constructor.h; sourceTree = "<group>"; };
+ 694120460B8A34AB00AF661E /* fastlog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fastlog.h; sourceTree = "<group>"; };
+ 694120470B8A34AB00AF661E /* forkexec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = forkexec.h; sourceTree = "<group>"; };
+ 694120480B8A34AB00AF661E /* id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = id.h; sourceTree = "<group>"; };
+ 694120490B8A34AB00AF661E /* mathfix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mathfix.h; sourceTree = "<group>"; };
+ 6941204A0B8A34AB00AF661E /* memento_command.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memento_command.h; sourceTree = "<group>"; };
+ 6941204B0B8A34AB00AF661E /* mountpoint.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mountpoint.h; sourceTree = "<group>"; };
+ 6941204C0B8A34AB00AF661E /* path.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = path.h; sourceTree = "<group>"; };
+ 6941204D0B8A34AB00AF661E /* pathscanner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pathscanner.h; sourceTree = "<group>"; };
+ 6941204E0B8A34AB00AF661E /* pool.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pool.h; sourceTree = "<group>"; };
+ 6941204F0B8A34AB00AF661E /* pthread_utils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pthread_utils.h; sourceTree = "<group>"; };
+ 694120500B8A34AB00AF661E /* rcu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rcu.h; sourceTree = "<group>"; };
+ 694120510B8A34AB00AF661E /* receiver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = receiver.h; sourceTree = "<group>"; };
+ 694120520B8A34AB00AF661E /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = "<group>"; };
+ 694120530B8A34AB00AF661E /* ringbufferNPT.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ringbufferNPT.h; sourceTree = "<group>"; };
+ 694120540B8A34AB00AF661E /* selectable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = selectable.h; sourceTree = "<group>"; };
+ 694120550B8A34AB00AF661E /* shiva.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = shiva.h; sourceTree = "<group>"; };
+ 694120560B8A34AB00AF661E /* stacktrace.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stacktrace.h; sourceTree = "<group>"; };
+ 694120570B8A34AB00AF661E /* stateful.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stateful.h; sourceTree = "<group>"; };
+ 694120580B8A34AB00AF661E /* statefuldestructible.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = statefuldestructible.h; sourceTree = "<group>"; };
+ 694120590B8A34AB00AF661E /* stl_delete.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stl_delete.h; sourceTree = "<group>"; };
+ 6941205A0B8A34AB00AF661E /* stl_functors.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stl_functors.h; sourceTree = "<group>"; };
+ 6941205B0B8A34AB00AF661E /* strsplit.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = strsplit.h; sourceTree = "<group>"; };
+ 6941205C0B8A34AB00AF661E /* textreceiver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = textreceiver.h; sourceTree = "<group>"; };
+ 6941205D0B8A34AB00AF661E /* thrown_error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = thrown_error.h; sourceTree = "<group>"; };
+ 6941205E0B8A34AB00AF661E /* tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = tokenizer.h; sourceTree = "<group>"; };
+ 6941205F0B8A34AB00AF661E /* touchable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = touchable.h; sourceTree = "<group>"; };
+ 694120600B8A34AB00AF661E /* transmitter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = transmitter.h; sourceTree = "<group>"; };
+ 694120610B8A34AB00AF661E /* undo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = undo.h; sourceTree = "<group>"; };
+ 694120620B8A34AB00AF661E /* whitespace.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = whitespace.h; sourceTree = "<group>"; };
+ 694120630B8A34AB00AF661E /* xml++.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "xml++.h"; sourceTree = "<group>"; };
+ 694120640B8A34AB00AF661E /* pool.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pool.cc; path = ../pool.cc; sourceTree = SOURCE_ROOT; };
+ 694120650B8A34AB00AF661E /* pthread_utils.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pthread_utils.cc; path = ../pthread_utils.cc; sourceTree = SOURCE_ROOT; };
+ 694120660B8A34AB00AF661E /* receiver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = receiver.cc; path = ../receiver.cc; sourceTree = SOURCE_ROOT; };
+ 694120670B8A34AB00AF661E /* stacktrace.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stacktrace.cc; path = ../stacktrace.cc; sourceTree = SOURCE_ROOT; };
+ 694120680B8A34AB00AF661E /* stateful.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stateful.cc; path = ../stateful.cc; sourceTree = SOURCE_ROOT; };
+ 694120690B8A34AB00AF661E /* strsplit.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = strsplit.cc; path = ../strsplit.cc; sourceTree = SOURCE_ROOT; };
+ 6941206A0B8A34AB00AF661E /* textreceiver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = textreceiver.cc; path = ../textreceiver.cc; sourceTree = SOURCE_ROOT; };
+ 6941206B0B8A34AB00AF661E /* transmitter.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = transmitter.cc; path = ../transmitter.cc; sourceTree = SOURCE_ROOT; };
+ 6941206C0B8A34AB00AF661E /* undo.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = undo.cc; path = ../undo.cc; sourceTree = SOURCE_ROOT; };
+ 6941206D0B8A34AB00AF661E /* whitespace.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = whitespace.cc; path = ../whitespace.cc; sourceTree = SOURCE_ROOT; };
+ 6941206E0B8A34AB00AF661E /* xml++.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = "xml++.cc"; path = "../xml++.cc"; sourceTree = SOURCE_ROOT; };
+ 694120D30B8A36A200AF661E /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = /usr/lib/libxml2.dylib; sourceTree = "<absolute>"; };
+ 694191950B97CD950083505E /* glibmm.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = glibmm.framework; path = /Library/Frameworks/glibmm.framework; sourceTree = "<absolute>"; };
+ 694191960B97CD950083505E /* sigc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = sigc.framework; path = /Library/Frameworks/sigc.framework; sourceTree = "<absolute>"; };
+ 69C63C140B9369CB00BC0BCA /* strreplace.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = strreplace.cc; path = ../strreplace.cc; sourceTree = SOURCE_ROOT; };
+ 69C63C180B9369DE00BC0BCA /* replace_all.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = replace_all.h; sourceTree = "<group>"; };
+ 69C63C290B936A6E00BC0BCA /* version.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = version.cc; sourceTree = "<group>"; };
+ 69C63C2A0B936A6E00BC0BCA /* version.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
+ 69CD7FE90B97CDD50049ED98 /* glib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = glib; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/glib; sourceTree = "<absolute>"; };
+ 69CD7FEA0B97CDD50049ED98 /* gmodule */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gmodule; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gmodule; sourceTree = "<absolute>"; };
+ 69CD7FEB0B97CDD50049ED98 /* gobject */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gobject; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gobject; sourceTree = "<absolute>"; };
+ 69CD7FEC0B97CDD50049ED98 /* gthread */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = gthread; path = /Library/Frameworks/GLib.framework/Versions/2.12.3/Libraries/gthread; sourceTree = "<absolute>"; };
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ 8D07F2C80486CC7A007CD1D0 /* pbd.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = pbd.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 694120D40B8A36A200AF661E /* libxml2.dylib in Frameworks */,
+ 694191980B97CD950083505E /* glibmm.framework in Frameworks */,
+ 694191990B97CD950083505E /* sigc.framework in Frameworks */,
+ 69CD7FED0B97CDD50049ED98 /* glib in Frameworks */,
+ 69CD7FEE0B97CDD50049ED98 /* gmodule in Frameworks */,
+ 69CD7FEF0B97CDD50049ED98 /* gobject in Frameworks */,
+ 69CD7FF00B97CDD50049ED98 /* gthread in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C80486CC7A007CD1D0 /* pbd.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* pbd */ = {
+ isa = PBXGroup;
+ children = (
+ 69C63C290B936A6E00BC0BCA /* version.cc */,
+ 69C63C2A0B936A6E00BC0BCA /* version.h */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 089C1665FE841158C02AAC07 /* Resources */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = pbd;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 69CD7FE90B97CDD50049ED98 /* glib */,
+ 69CD7FEA0B97CDD50049ED98 /* gmodule */,
+ 69CD7FEB0B97CDD50049ED98 /* gobject */,
+ 69CD7FEC0B97CDD50049ED98 /* gthread */,
+ 694191950B97CD950083505E /* glibmm.framework */,
+ 694191960B97CD950083505E /* sigc.framework */,
+ 694120D30B8A36A200AF661E /* libxml2.dylib */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C1665FE841158C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */,
+ 089C1666FE841158C02AAC07 /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 69C63C140B9369CB00BC0BCA /* strreplace.cc */,
+ 694120270B8A34AB00AF661E /* base_ui.cc */,
+ 694120280B8A34AB00AF661E /* basename.cc */,
+ 694120290B8A34AB00AF661E /* command.cc */,
+ 6941202A0B8A34AB00AF661E /* controllable.cc */,
+ 6941202B0B8A34AB00AF661E /* convert.cc */,
+ 6941202C0B8A34AB00AF661E /* copyfile.cc */,
+ 6941202D0B8A34AB00AF661E /* dmalloc.cc */,
+ 6941202E0B8A34AB00AF661E /* enumwriter.cc */,
+ 6941202F0B8A34AB00AF661E /* error.cc */,
+ 694120300B8A34AB00AF661E /* gettext.h */,
+ 694120310B8A34AB00AF661E /* i18n.h */,
+ 694120320B8A34AB00AF661E /* id.cc */,
+ 694120330B8A34AB00AF661E /* mountpoint.cc */,
+ 694120340B8A34AB00AF661E /* path.cc */,
+ 694120350B8A34AB00AF661E /* pathscanner.cc */,
+ 694120360B8A34AB00AF661E /* pbd */,
+ 694120640B8A34AB00AF661E /* pool.cc */,
+ 694120650B8A34AB00AF661E /* pthread_utils.cc */,
+ 694120660B8A34AB00AF661E /* receiver.cc */,
+ 694120670B8A34AB00AF661E /* stacktrace.cc */,
+ 694120680B8A34AB00AF661E /* stateful.cc */,
+ 694120690B8A34AB00AF661E /* strsplit.cc */,
+ 6941206A0B8A34AB00AF661E /* textreceiver.cc */,
+ 6941206B0B8A34AB00AF661E /* transmitter.cc */,
+ 6941206C0B8A34AB00AF661E /* undo.cc */,
+ 6941206D0B8A34AB00AF661E /* whitespace.cc */,
+ 6941206E0B8A34AB00AF661E /* xml++.cc */,
+ 32BAE0B70371A74B00C91783 /* pbd_Prefix.pch */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 694120360B8A34AB00AF661E /* pbd */ = {
+ isa = PBXGroup;
+ children = (
+ 69C63C180B9369DE00BC0BCA /* replace_all.h */,
+ 694120380B8A34AB00AF661E /* abstract_ui.cc */,
+ 694120390B8A34AB00AF661E /* abstract_ui.h */,
+ 6941203A0B8A34AB00AF661E /* base_ui.h */,
+ 6941203B0B8A34AB00AF661E /* basename.h */,
+ 6941203C0B8A34AB00AF661E /* command.h */,
+ 6941203D0B8A34AB00AF661E /* compose.h */,
+ 6941203E0B8A34AB00AF661E /* controllable.h */,
+ 6941203F0B8A34AB00AF661E /* convert.h */,
+ 694120400B8A34AB00AF661E /* copyfile.h */,
+ 694120410B8A34AB00AF661E /* crossthread.h */,
+ 694120420B8A34AB00AF661E /* destructible.h */,
+ 694120430B8A34AB00AF661E /* enumwriter.h */,
+ 694120440B8A34AB00AF661E /* error.h */,
+ 694120450B8A34AB00AF661E /* failed_constructor.h */,
+ 694120460B8A34AB00AF661E /* fastlog.h */,
+ 694120470B8A34AB00AF661E /* forkexec.h */,
+ 694120480B8A34AB00AF661E /* id.h */,
+ 694120490B8A34AB00AF661E /* mathfix.h */,
+ 6941204A0B8A34AB00AF661E /* memento_command.h */,
+ 6941204B0B8A34AB00AF661E /* mountpoint.h */,
+ 6941204C0B8A34AB00AF661E /* path.h */,
+ 6941204D0B8A34AB00AF661E /* pathscanner.h */,
+ 6941204E0B8A34AB00AF661E /* pool.h */,
+ 6941204F0B8A34AB00AF661E /* pthread_utils.h */,
+ 694120500B8A34AB00AF661E /* rcu.h */,
+ 694120510B8A34AB00AF661E /* receiver.h */,
+ 694120520B8A34AB00AF661E /* ringbuffer.h */,
+ 694120530B8A34AB00AF661E /* ringbufferNPT.h */,
+ 694120540B8A34AB00AF661E /* selectable.h */,
+ 694120550B8A34AB00AF661E /* shiva.h */,
+ 694120560B8A34AB00AF661E /* stacktrace.h */,
+ 694120570B8A34AB00AF661E /* stateful.h */,
+ 694120580B8A34AB00AF661E /* statefuldestructible.h */,
+ 694120590B8A34AB00AF661E /* stl_delete.h */,
+ 6941205A0B8A34AB00AF661E /* stl_functors.h */,
+ 6941205B0B8A34AB00AF661E /* strsplit.h */,
+ 6941205C0B8A34AB00AF661E /* textreceiver.h */,
+ 6941205D0B8A34AB00AF661E /* thrown_error.h */,
+ 6941205E0B8A34AB00AF661E /* tokenizer.h */,
+ 6941205F0B8A34AB00AF661E /* touchable.h */,
+ 694120600B8A34AB00AF661E /* transmitter.h */,
+ 694120610B8A34AB00AF661E /* undo.h */,
+ 694120620B8A34AB00AF661E /* whitespace.h */,
+ 694120630B8A34AB00AF661E /* xml++.h */,
+ );
+ name = pbd;
+ path = ../pbd;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 69C63C2C0B936A6E00BC0BCA /* version.h in Headers */,
+ 69C63C190B9369DE00BC0BCA /* replace_all.h in Headers */,
+ 8D07F2BE0486CC7A007CD1D0 /* pbd_Prefix.pch in Headers */,
+ 6941207F0B8A34AB00AF661E /* abstract_ui.cc in Headers */,
+ 694120780B8A34AB00AF661E /* gettext.h in Headers */,
+ 694120790B8A34AB00AF661E /* i18n.h in Headers */,
+ 694120800B8A34AB00AF661E /* abstract_ui.h in Headers */,
+ 694120810B8A34AB00AF661E /* base_ui.h in Headers */,
+ 694120820B8A34AB00AF661E /* basename.h in Headers */,
+ 694120830B8A34AB00AF661E /* command.h in Headers */,
+ 694120840B8A34AB00AF661E /* compose.h in Headers */,
+ 694120850B8A34AB00AF661E /* controllable.h in Headers */,
+ 694120860B8A34AB00AF661E /* convert.h in Headers */,
+ 694120870B8A34AB00AF661E /* copyfile.h in Headers */,
+ 694120880B8A34AB00AF661E /* crossthread.h in Headers */,
+ 694120890B8A34AB00AF661E /* destructible.h in Headers */,
+ 6941208A0B8A34AB00AF661E /* enumwriter.h in Headers */,
+ 6941208B0B8A34AB00AF661E /* error.h in Headers */,
+ 6941208C0B8A34AB00AF661E /* failed_constructor.h in Headers */,
+ 6941208D0B8A34AB00AF661E /* fastlog.h in Headers */,
+ 6941208E0B8A34AB00AF661E /* forkexec.h in Headers */,
+ 6941208F0B8A34AB00AF661E /* id.h in Headers */,
+ 694120900B8A34AB00AF661E /* mathfix.h in Headers */,
+ 694120910B8A34AB00AF661E /* memento_command.h in Headers */,
+ 694120920B8A34AB00AF661E /* mountpoint.h in Headers */,
+ 694120930B8A34AB00AF661E /* path.h in Headers */,
+ 694120940B8A34AB00AF661E /* pathscanner.h in Headers */,
+ 694120950B8A34AB00AF661E /* pool.h in Headers */,
+ 694120960B8A34AB00AF661E /* pthread_utils.h in Headers */,
+ 694120970B8A34AB00AF661E /* rcu.h in Headers */,
+ 694120980B8A34AB00AF661E /* receiver.h in Headers */,
+ 694120990B8A34AB00AF661E /* ringbuffer.h in Headers */,
+ 6941209A0B8A34AB00AF661E /* ringbufferNPT.h in Headers */,
+ 6941209B0B8A34AB00AF661E /* selectable.h in Headers */,
+ 6941209C0B8A34AB00AF661E /* shiva.h in Headers */,
+ 6941209D0B8A34AB00AF661E /* stacktrace.h in Headers */,
+ 6941209E0B8A34AB00AF661E /* stateful.h in Headers */,
+ 6941209F0B8A34AB00AF661E /* statefuldestructible.h in Headers */,
+ 694120A00B8A34AB00AF661E /* stl_delete.h in Headers */,
+ 694120A10B8A34AB00AF661E /* stl_functors.h in Headers */,
+ 694120A20B8A34AB00AF661E /* strsplit.h in Headers */,
+ 694120A30B8A34AB00AF661E /* textreceiver.h in Headers */,
+ 694120A40B8A34AB00AF661E /* thrown_error.h in Headers */,
+ 694120A50B8A34AB00AF661E /* tokenizer.h in Headers */,
+ 694120A60B8A34AB00AF661E /* touchable.h in Headers */,
+ 694120A70B8A34AB00AF661E /* transmitter.h in Headers */,
+ 694120A80B8A34AB00AF661E /* undo.h in Headers */,
+ 694120A90B8A34AB00AF661E /* whitespace.h in Headers */,
+ 694120AA0B8A34AB00AF661E /* xml++.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 8D07F2BC0486CC7A007CD1D0 /* pbd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "pbd" */;
+ buildPhases = (
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */,
+ 8D07F2C50486CC7A007CD1D0 /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pbd;
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = pbd;
+ productReference = 8D07F2C80486CC7A007CD1D0 /* pbd.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "pbd" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* pbd */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* pbd */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8D07F2C50486CC7A007CD1D0 /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 69C63C2B0B936A6E00BC0BCA /* version.cc in Sources */,
+ 6941206F0B8A34AB00AF661E /* base_ui.cc in Sources */,
+ 69C63C150B9369CB00BC0BCA /* strreplace.cc in Sources */,
+ 694120700B8A34AB00AF661E /* basename.cc in Sources */,
+ 694120710B8A34AB00AF661E /* command.cc in Sources */,
+ 694120720B8A34AB00AF661E /* controllable.cc in Sources */,
+ 694120730B8A34AB00AF661E /* convert.cc in Sources */,
+ 694120740B8A34AB00AF661E /* copyfile.cc in Sources */,
+ 694120750B8A34AB00AF661E /* dmalloc.cc in Sources */,
+ 694120760B8A34AB00AF661E /* enumwriter.cc in Sources */,
+ 694120770B8A34AB00AF661E /* error.cc in Sources */,
+ 6941207A0B8A34AB00AF661E /* id.cc in Sources */,
+ 6941207B0B8A34AB00AF661E /* mountpoint.cc in Sources */,
+ 6941207C0B8A34AB00AF661E /* path.cc in Sources */,
+ 6941207D0B8A34AB00AF661E /* pathscanner.cc in Sources */,
+ 694120AB0B8A34AB00AF661E /* pool.cc in Sources */,
+ 694120AC0B8A34AB00AF661E /* pthread_utils.cc in Sources */,
+ 694120AD0B8A34AB00AF661E /* receiver.cc in Sources */,
+ 694120AE0B8A34AB00AF661E /* stacktrace.cc in Sources */,
+ 694120AF0B8A34AB00AF661E /* stateful.cc in Sources */,
+ 694120B00B8A34AB00AF661E /* strsplit.cc in Sources */,
+ 694120B10B8A34AB00AF661E /* textreceiver.cc in Sources */,
+ 694120B20B8A34AB00AF661E /* transmitter.cc in Sources */,
+ 694120B30B8A34AB00AF661E /* undo.cc in Sources */,
+ 694120B40B8A34AB00AF661E /* whitespace.cc in Sources */,
+ 694120B50B8A34AB00AF661E /* xml++.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 089C1667FE841158C02AAC07 /* English */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = pbd_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ PRODUCT_NAME = pbd;
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Release;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ "$(NATIVE_ARCH)",
+ ppc,
+ );
+ GCC_FAST_OBJC_DISPATCH = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_STRICT_ALIASING = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ /usr/include/libxml2,
+ /Library/Frameworks/GLib.framework/Headers,
+ /Library/Frameworks/glibmm.framework/Headers,
+ /Library/Frameworks/sigc.framework/Headers,
+ );
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+ 69C9AF150B97A83A0097DE90 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(NATIVE_ARCH)";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = stabs;
+ GCC_FAST_OBJC_DISPATCH = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ /usr/include/libxml2,
+ /Library/Frameworks/GLib.framework/Headers,
+ /Library/Frameworks/glibmm.framework/Headers,
+ /Library/Frameworks/sigc.framework/Headers,
+ );
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ STRIP_INSTALLED_PRODUCT = NO;
+ };
+ name = Debug;
+ };
+ 69C9AF160B97A83A0097DE90 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = i386;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = pbd_Prefix.pch;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@executable_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(LOCAL_LIBRARY_DIR)/Frameworks/GLib.framework/Versions/2.12.3/Libraries\"";
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ PRODUCT_NAME = pbd;
+ WRAPPER_EXTENSION = framework;
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "pbd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24408B4156D00ABE55E /* Release */,
+ 69C9AF160B97A83A0097DE90 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "pbd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24808B4156D00ABE55E /* Release */,
+ 69C9AF150B97A83A0097DE90 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/libs/pbd/macosx/pbd_Prefix.pch b/libs/pbd/macosx/pbd_Prefix.pch
new file mode 100644
index 0000000000..a774fac593
--- /dev/null
+++ b/libs/pbd/macosx/pbd_Prefix.pch
@@ -0,0 +1,4 @@
+//
+// Prefix header for all source files of the 'pbd' target in the 'pbd' project.
+//
+
diff --git a/libs/pbd/macosx/version.cc b/libs/pbd/macosx/version.cc
new file mode 100644
index 0000000000..61a94f6fc9
--- /dev/null
+++ b/libs/pbd/macosx/version.cc
@@ -0,0 +1,3 @@
+int libpbd_major_version = 4;
+int libpbd_minor_version = 1;
+int libpbd_micro_version = 0;
diff --git a/libs/pbd/macosx/version.h b/libs/pbd/macosx/version.h
new file mode 100644
index 0000000000..ec6c854141
--- /dev/null
+++ b/libs/pbd/macosx/version.h
@@ -0,0 +1,7 @@
+#ifndef __libpbd_version_h__
+#define __libpbd_version_h__
+extern const char* libpbd_revision;
+extern int libpbd_major_version;
+extern int libpbd_minor_version;
+extern int libpbd_micro_version;
+#endif /* __libpbd_version_h__ */
diff --git a/libs/pbd/pbd/abstract_ui.cc b/libs/pbd/pbd/abstract_ui.cc
index eca53916af..97f19e1fe5 100644
--- a/libs/pbd/pbd/abstract_ui.cc
+++ b/libs/pbd/pbd/abstract_ui.cc
@@ -54,6 +54,8 @@ AbstractUI<RequestObject>::get_request (RequestType rt)
}
RequestBufferVector vec;
+ vec.buf[0] = 0;
+ vec.buf[1] = 0;
rbuf->get_write_vector (&vec);
@@ -100,16 +102,10 @@ AbstractUI<RequestObject>::handle_ui_requests ()
if (vec.len[0] == 0) {
break;
} else {
- /* request_factory/copy constructor does a deep
- copy of the Request object,
- unlike Ringbuffer::read()
- */
-
- RequestObject req (*vec.buf[0]);
- i->second->increment_read_ptr (1);
request_buffer_map_lock.unlock ();
- do_request (&req);
+ do_request (vec.buf[0]);
request_buffer_map_lock.lock ();
+ i->second->increment_read_ptr (1);
}
}
}
diff --git a/libs/pbd/pbd/abstract_ui.h b/libs/pbd/pbd/abstract_ui.h
index f80db7bf1a..88c27aa0bc 100644
--- a/libs/pbd/pbd/abstract_ui.h
+++ b/libs/pbd/pbd/abstract_ui.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_abstract_ui_h__
diff --git a/libs/pbd/pbd/command.h b/libs/pbd/pbd/command.h
index 8044b51a83..23bcf85b91 100644
--- a/libs/pbd/pbd/command.h
+++ b/libs/pbd/pbd/command.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: /local/undo/libs/pbd3/pbd/undo.h 80 2006-06-22T22:37:01.079855Z fugalh $
*/
#ifndef __lib_pbd_command_h__
diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h
index c88eb298bc..c152013c66 100644
--- a/libs/pbd/pbd/controllable.h
+++ b/libs/pbd/pbd/controllable.h
@@ -2,6 +2,7 @@
#define __pbd_controllable_h__
#include <string>
+#include <set>
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
@@ -36,8 +37,18 @@ class Controllable : public PBD::StatefulDestructible {
std::string name() const { return _name; }
+ static Controllable* by_id (const PBD::ID&);
+ static Controllable* by_name (const std::string&);
+
private:
std::string _name;
+
+ void add ();
+ void remove ();
+
+ typedef std::set<PBD::Controllable*> Controllables;
+ static Glib::Mutex* registry_lock;
+ static Controllables registry;
};
}
diff --git a/libs/pbd/pbd/error.h b/libs/pbd/pbd/error.h
index 4136f02ee2..58842d68eb 100644
--- a/libs/pbd/pbd/error.h
+++ b/libs/pbd/pbd/error.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __libpbd_error_h__
#define __libpbd_error_h__
diff --git a/libs/pbd/pbd/mathfix.h b/libs/pbd/pbd/mathfix.h
index f0dc7e491e..fd0468905f 100644
--- a/libs/pbd/pbd/mathfix.h
+++ b/libs/pbd/pbd/mathfix.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_mathfix_h__
diff --git a/libs/pbd/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h
index fe1aa8e7d0..d913b2c0fe 100644
--- a/libs/pbd/pbd/memento_command.h
+++ b/libs/pbd/pbd/memento_command.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: /local/undo/libs/pbd3/pbd/undo.h 132 2006-06-29T18:45:16.609763Z fugalh $
*/
#ifndef __lib_pbd_memento_command_h__
diff --git a/libs/pbd/pbd/mountpoint.h b/libs/pbd/pbd/mountpoint.h
index 86ccc58190..e0ec1be7f9 100644
--- a/libs/pbd/pbd/mountpoint.h
+++ b/libs/pbd/pbd/mountpoint.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_mountpoint_h__
diff --git a/libs/pbd/pbd/pool.h b/libs/pbd/pbd/pool.h
index f8e19e72fb..d604680ae2 100644
--- a/libs/pbd/pbd/pool.h
+++ b/libs/pbd/pbd/pool.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __qm_pool_h__
diff --git a/libs/pbd/pbd/rcu.h b/libs/pbd/pbd/rcu.h
index a8f3cdd5bc..8b0b8b3548 100644
--- a/libs/pbd/pbd/rcu.h
+++ b/libs/pbd/pbd/rcu.h
@@ -12,22 +12,21 @@ class RCUManager
public:
RCUManager (T* new_rcu_value) {
- m_rcu_value = new boost::shared_ptr<T> (new_rcu_value);
+ x.m_rcu_value = new boost::shared_ptr<T> (new_rcu_value);
}
- virtual ~RCUManager() { delete m_rcu_value; }
+ virtual ~RCUManager() { delete x.m_rcu_value; }
- boost::shared_ptr<T> reader () const { return *((boost::shared_ptr<T> *) g_atomic_pointer_get (the_pointer())); }
+ boost::shared_ptr<T> reader () const { return *((boost::shared_ptr<T> *) g_atomic_pointer_get (&x.gptr)); }
virtual boost::shared_ptr<T> write_copy () = 0;
virtual bool update (boost::shared_ptr<T> new_value) = 0;
protected:
- boost::shared_ptr<T>* m_rcu_value;
-
- // this monstrosity is needed because of some wierd behavior by g++
-
- gpointer * the_pointer() const { return (gpointer *) &m_rcu_value; }
+ union {
+ boost::shared_ptr<T>* m_rcu_value;
+ mutable volatile gpointer gptr;
+ } x;
};
@@ -60,7 +59,7 @@ public:
// store the current
- current_write_old = RCUManager<T>::m_rcu_value;
+ current_write_old = RCUManager<T>::x.m_rcu_value;
boost::shared_ptr<T> new_copy (new T(**current_write_old));
@@ -76,7 +75,7 @@ public:
// update, checking that nobody beat us to it
- bool ret = g_atomic_pointer_compare_and_exchange (RCUManager<T>::the_pointer(),
+ bool ret = g_atomic_pointer_compare_and_exchange (&RCUManager<T>::x.gptr,
(gpointer) current_write_old,
(gpointer) new_spp);
diff --git a/libs/pbd/pbd/receiver.h b/libs/pbd/pbd/receiver.h
index 5ce238df63..93192ce787 100644
--- a/libs/pbd/pbd/receiver.h
+++ b/libs/pbd/pbd/receiver.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __libmisc_receiver_h__
diff --git a/libs/pbd/pbd/replace_all.h b/libs/pbd/pbd/replace_all.h
new file mode 100644
index 0000000000..4434637283
--- /dev/null
+++ b/libs/pbd/pbd/replace_all.h
@@ -0,0 +1,8 @@
+#ifndef __pbd_replace_all_h__
+#define __pbd_replace_all_h__
+
+#include <string>
+
+int replace_all (std::string& str, const std::string& target, const std::string& replacement);
+
+#endif // __pbd_replace_all_h__
diff --git a/libs/pbd/pbd/ringbuffer.h b/libs/pbd/pbd/ringbuffer.h
index 1d9c9b04e3..d98601461e 100644
--- a/libs/pbd/pbd/ringbuffer.h
+++ b/libs/pbd/pbd/ringbuffer.h
@@ -15,25 +15,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef ringbuffer_h
#define ringbuffer_h
-//#include <sys/mman.h>
-
#include <glib.h>
template<class T>
class RingBuffer
{
public:
- RingBuffer (size_t sz) {
- size_t power_of_two;
-
- for (power_of_two = 1; 1U<<power_of_two < sz; power_of_two++);
-
+ RingBuffer (guint sz) {
+// size = ffs(sz); /* find first [bit] set is a single inlined assembly instruction. But it looks like the API rounds up so... */
+ guint power_of_two;
+ for (power_of_two = 1; 1U<<power_of_two < sz; power_of_two++);
size = 1<<power_of_two;
size_mask = size;
size_mask -= 1;
@@ -48,44 +44,44 @@ class RingBuffer
void reset () {
/* !!! NOT THREAD SAFE !!! */
- g_atomic_int_set (&write_ptr, 0);
- g_atomic_int_set (&read_ptr, 0);
+ g_atomic_int_set (&write_idx, 0);
+ g_atomic_int_set (&read_idx, 0);
}
- void set (size_t r, size_t w) {
+ void set (guint r, guint w) {
/* !!! NOT THREAD SAFE !!! */
- g_atomic_int_set (&write_ptr, w);
- g_atomic_int_set (&read_ptr, r);
+ g_atomic_int_set (&write_idx, w);
+ g_atomic_int_set (&read_idx, r);
}
- size_t read (T *dest, size_t cnt);
- size_t write (T *src, size_t cnt);
+ guint read (T *dest, guint cnt);
+ guint write (T *src, guint cnt);
struct rw_vector {
T *buf[2];
- size_t len[2];
+ guint len[2];
};
void get_read_vector (rw_vector *);
void get_write_vector (rw_vector *);
- void decrement_read_ptr (size_t cnt) {
- g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) - cnt) & size_mask);
+ void decrement_read_idx (guint cnt) {
+ g_atomic_int_set (&read_idx, (g_atomic_int_get(&read_idx) - cnt) & size_mask);
}
- void increment_read_ptr (size_t cnt) {
- g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) + cnt) & size_mask);
+ void increment_read_idx (guint cnt) {
+ g_atomic_int_set (&read_idx, (g_atomic_int_get(&read_idx) + cnt) & size_mask);
}
- void increment_write_ptr (size_t cnt) {
- g_atomic_int_set (&write_ptr, (g_atomic_int_get(&write_ptr) + cnt) & size_mask);
+ void increment_write_idx (guint cnt) {
+ g_atomic_int_set (&write_idx, (g_atomic_int_get(&write_idx) + cnt) & size_mask);
}
- size_t write_space () {
- size_t w, r;
+ guint write_space () {
+ guint w, r;
- w = g_atomic_int_get (&write_ptr);
- r = g_atomic_int_get (&read_ptr);
+ w = g_atomic_int_get (&write_idx);
+ r = g_atomic_int_get (&read_idx);
if (w > r) {
return ((r - w + size) & size_mask) - 1;
@@ -96,11 +92,11 @@ class RingBuffer
}
}
- size_t read_space () {
- size_t w, r;
+ guint read_space () {
+ guint w, r;
- w = g_atomic_int_get (&write_ptr);
- r = g_atomic_int_get (&read_ptr);
+ w = g_atomic_int_get (&write_idx);
+ r = g_atomic_int_get (&read_idx);
if (w > r) {
return w - r;
@@ -110,28 +106,28 @@ class RingBuffer
}
T *buffer () { return buf; }
- size_t get_write_ptr () const { return g_atomic_int_get (&write_ptr); }
- size_t get_read_ptr () const { return g_atomic_int_get (&read_ptr); }
- size_t bufsize () const { return size; }
+ guint get_write_idx () const { return g_atomic_int_get (&write_idx); }
+ guint get_read_idx () const { return g_atomic_int_get (&read_idx); }
+ guint bufsize () const { return size; }
protected:
T *buf;
- size_t size;
- mutable gint write_ptr;
- mutable gint read_ptr;
- size_t size_mask;
+ guint size;
+ mutable gint write_idx;
+ mutable gint read_idx;
+ guint size_mask;
};
-template<class T> size_t
-RingBuffer<T>::read (T *dest, size_t cnt)
+template<class T> guint
+RingBuffer<T>::read (T *dest, guint cnt)
{
- size_t free_cnt;
- size_t cnt2;
- size_t to_read;
- size_t n1, n2;
- size_t priv_read_ptr;
+ guint free_cnt;
+ guint cnt2;
+ guint to_read;
+ guint n1, n2;
+ guint priv_read_idx;
- priv_read_ptr=g_atomic_int_get(&read_ptr);
+ priv_read_idx=g_atomic_int_get(&read_idx);
if ((free_cnt = read_space ()) == 0) {
return 0;
@@ -139,39 +135,39 @@ RingBuffer<T>::read (T *dest, size_t cnt)
to_read = cnt > free_cnt ? free_cnt : cnt;
- cnt2 = priv_read_ptr + to_read;
+ cnt2 = priv_read_idx + to_read;
if (cnt2 > size) {
- n1 = size - priv_read_ptr;
+ n1 = size - priv_read_idx;
n2 = cnt2 & size_mask;
} else {
n1 = to_read;
n2 = 0;
}
- memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));
- priv_read_ptr = (priv_read_ptr + n1) & size_mask;
+ memcpy (dest, &buf[priv_read_idx], n1 * sizeof (T));
+ priv_read_idx = (priv_read_idx + n1) & size_mask;
if (n2) {
memcpy (dest+n1, buf, n2 * sizeof (T));
- priv_read_ptr = n2;
+ priv_read_idx = n2;
}
- g_atomic_int_set(&read_ptr, priv_read_ptr);
+ g_atomic_int_set(&read_idx, priv_read_idx);
return to_read;
}
-template<class T> size_t
-RingBuffer<T>::write (T *src, size_t cnt)
+template<class T> guint
+RingBuffer<T>::write (T *src, guint cnt)
{
- size_t free_cnt;
- size_t cnt2;
- size_t to_write;
- size_t n1, n2;
- size_t priv_write_ptr;
+ guint free_cnt;
+ guint cnt2;
+ guint to_write;
+ guint n1, n2;
+ guint priv_write_idx;
- priv_write_ptr=g_atomic_int_get(&write_ptr);
+ priv_write_idx=g_atomic_int_get(&write_idx);
if ((free_cnt = write_space ()) == 0) {
return 0;
@@ -179,25 +175,25 @@ RingBuffer<T>::write (T *src, size_t cnt)
to_write = cnt > free_cnt ? free_cnt : cnt;
- cnt2 = priv_write_ptr + to_write;
+ cnt2 = priv_write_idx + to_write;
if (cnt2 > size) {
- n1 = size - priv_write_ptr;
+ n1 = size - priv_write_idx;
n2 = cnt2 & size_mask;
} else {
n1 = to_write;
n2 = 0;
}
- memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));
- priv_write_ptr = (priv_write_ptr + n1) & size_mask;
+ memcpy (&buf[priv_write_idx], src, n1 * sizeof (T));
+ priv_write_idx = (priv_write_idx + n1) & size_mask;
if (n2) {
memcpy (buf, src+n1, n2 * sizeof (T));
- priv_write_ptr = n2;
+ priv_write_idx = n2;
}
- g_atomic_int_set(&write_ptr, priv_write_ptr);
+ g_atomic_int_set(&write_idx, priv_write_idx);
return to_write;
}
@@ -205,12 +201,12 @@ template<class T> void
RingBuffer<T>::get_read_vector (RingBuffer<T>::rw_vector *vec)
{
- size_t free_cnt;
- size_t cnt2;
- size_t w, r;
+ guint free_cnt;
+ guint cnt2;
+ guint w, r;
- w = g_atomic_int_get (&write_ptr);
- r = g_atomic_int_get (&read_ptr);
+ w = g_atomic_int_get (&write_idx);
+ r = g_atomic_int_get (&read_idx);
if (w > r) {
free_cnt = w - r;
@@ -245,12 +241,12 @@ template<class T> void
RingBuffer<T>::get_write_vector (RingBuffer<T>::rw_vector *vec)
{
- size_t free_cnt;
- size_t cnt2;
- size_t w, r;
+ guint free_cnt;
+ guint cnt2;
+ guint w, r;
- w = g_atomic_int_get (&write_ptr);
- r = g_atomic_int_get (&read_ptr);
+ w = g_atomic_int_get (&write_idx);
+ r = g_atomic_int_get (&read_idx);
if (w > r) {
free_cnt = ((r - w + size) & size_mask) - 1;
diff --git a/libs/pbd/pbd/ringbufferNPT.h b/libs/pbd/pbd/ringbufferNPT.h
index fee2efce3d..9db09098d6 100644
--- a/libs/pbd/pbd/ringbufferNPT.h
+++ b/libs/pbd/pbd/ringbufferNPT.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef ringbuffer_npt_h
diff --git a/libs/pbd/pbd/selectable.h b/libs/pbd/pbd/selectable.h
index 470bc3cfcc..85f3e79ab0 100644
--- a/libs/pbd/pbd/selectable.h
+++ b/libs/pbd/pbd/selectable.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __selectable_h__
diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h
index 5fbac11e5c..550db5a24e 100644
--- a/libs/pbd/pbd/stateful.h
+++ b/libs/pbd/pbd/stateful.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: stateful.h 17 2005-09-24 19:13:41Z taybin $
*/
#ifndef __pbd_stateful_h__
diff --git a/libs/pbd/pbd/stl_delete.h b/libs/pbd/pbd/stl_delete.h
index 6e5bfa0734..66fb027387 100644
--- a/libs/pbd/pbd/stl_delete.h
+++ b/libs/pbd/pbd/stl_delete.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __libmisc_stl_delete_h__
diff --git a/libs/pbd/pbd/stl_functors.h b/libs/pbd/pbd/stl_functors.h
index 4a96e91a28..3c83a1ae2f 100644
--- a/libs/pbd/pbd/stl_functors.h
+++ b/libs/pbd/pbd/stl_functors.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __stl_functors_h__
diff --git a/libs/pbd/pbd/strsplit.h b/libs/pbd/pbd/strsplit.h
index e55ad1c825..f36a3ae5f0 100644
--- a/libs/pbd/pbd/strsplit.h
+++ b/libs/pbd/pbd/strsplit.h
@@ -3,7 +3,9 @@
#include <string>
#include <vector>
+#include <glibmm/ustring.h>
extern void split (std::string, std::vector<std::string>&, char);
+extern void split (Glib::ustring, std::vector<Glib::ustring>&, char);
#endif // __pbd_strplit_h__
diff --git a/libs/pbd/pbd/textreceiver.h b/libs/pbd/pbd/textreceiver.h
index b8bfe5bc78..e5900fc652 100644
--- a/libs/pbd/pbd/textreceiver.h
+++ b/libs/pbd/pbd/textreceiver.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __libmisc_textreceiver_h__
diff --git a/libs/pbd/pbd/thrown_error.h b/libs/pbd/pbd/thrown_error.h
index 83cf8acfac..0a63085f11 100644
--- a/libs/pbd/pbd/thrown_error.h
+++ b/libs/pbd/pbd/thrown_error.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __qm_thrown_error_h__
#define __qm_thrown_error_h__
diff --git a/libs/pbd/pbd/touchable.h b/libs/pbd/pbd/touchable.h
index 0298574dfa..12f1c443fd 100644
--- a/libs/pbd/pbd/touchable.h
+++ b/libs/pbd/pbd/touchable.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_touchable_h__
diff --git a/libs/pbd/pbd/transmitter.h b/libs/pbd/pbd/transmitter.h
index 357cb9965f..61ac9bd8d8 100644
--- a/libs/pbd/pbd/transmitter.h
+++ b/libs/pbd/pbd/transmitter.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __libmisc_transmitter_h__
diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h
index 4dfab5178f..9539d8b41d 100644
--- a/libs/pbd/pbd/undo.h
+++ b/libs/pbd/pbd/undo.h
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __lib_pbd_undo_h__
diff --git a/libs/pbd/stacktrace.cc b/libs/pbd/stacktrace.cc
index a653fe3033..8a6eb606b2 100644
--- a/libs/pbd/stacktrace.cc
+++ b/libs/pbd/stacktrace.cc
@@ -23,7 +23,7 @@ PBD::stacktrace (std::ostream& out, int levels)
printf ("Obtained %zd stack frames.\n", size);
- for (i = 0; i < size && (levels == 0 || i < levels); i++) {
+ for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) {
out << strings[i] << std::endl;
}
@@ -39,4 +39,10 @@ PBD::stacktrace (std::ostream& out, int levels)
out << "stack tracing is not enabled on this platform" << std::endl;
}
+void
+c_stacktrace ()
+{
+ PBD::stacktrace (std::cout);
+}
+
#endif /* HAVE_EXECINFO */
diff --git a/libs/pbd/strreplace.cc b/libs/pbd/strreplace.cc
new file mode 100644
index 0000000000..dd90baf324
--- /dev/null
+++ b/libs/pbd/strreplace.cc
@@ -0,0 +1,19 @@
+#include <pbd/replace_all.h>
+
+int
+replace_all (std::string& str,
+ std::string const& target,
+ std::string const& replacement)
+{
+ std::string::size_type start = str.find (target, 0);
+ int cnt = 0;
+
+ while (start != std::string::npos) {
+ str.replace (start, target.size(), replacement);
+ start = str.find (target, start+replacement.size());
+ ++cnt;
+ }
+
+ return cnt;
+}
+
diff --git a/libs/pbd/strsplit.cc b/libs/pbd/strsplit.cc
index 7f29a77887..1fb6112150 100644
--- a/libs/pbd/strsplit.cc
+++ b/libs/pbd/strsplit.cc
@@ -1,6 +1,7 @@
#include <pbd/strsplit.h>
using namespace std;
+using namespace Glib;
void
split (string str, vector<string>& result, char splitchar)
@@ -39,3 +40,41 @@ split (string str, vector<string>& result, char splitchar)
result.push_back (remaining);
}
}
+
+void
+split (ustring str, vector<ustring>& result, char splitchar)
+{
+ ustring::size_type pos;
+ ustring remaining;
+ ustring::size_type len = str.length();
+ int cnt;
+
+ cnt = 0;
+
+ if (str.empty()) {
+ return;
+ }
+
+ for (ustring::size_type n = 0; n < len; ++n) {
+ if (str[n] == gunichar(splitchar)) {
+ cnt++;
+ }
+ }
+
+ if (cnt == 0) {
+ result.push_back (str);
+ return;
+ }
+
+ remaining = str;
+
+ while ((pos = remaining.find_first_of (':')) != ustring::npos) {
+ result.push_back (remaining.substr (0, pos));
+ remaining = remaining.substr (pos+1);
+ }
+
+ if (remaining.length()) {
+
+ result.push_back (remaining);
+ }
+}
diff --git a/libs/sigc++2/autogen.sh b/libs/sigc++2/autogen.sh
index ebb519d373..09597765c6 100755
--- a/libs/sigc++2/autogen.sh
+++ b/libs/sigc++2/autogen.sh
@@ -1,5 +1,26 @@
#! /bin/sh
+# check all tools first
+
+if /usr/bin/which libtoolize >/dev/null 2>&1 ; then
+ :
+else
+ echo "You do not have libtool installed, which is very sadly required to build part of Ardour"
+ exit 1
+fi
+if /usr/bin/which automake >/dev/null 2>&1 ; then
+ :
+else
+ echo "You do not have automake installed, which is very sadly required to build part of Ardour"
+ exit 1
+fi
+if /usr/bin/which autoconf >/dev/null 2>&1 ; then
+ :
+else
+ echo "You do not have autoconf installed, which is very sadly required to build part of Ardour"
+ exit 1
+fi
+
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
diff --git a/libs/soundtouch/RateTransposer.cpp b/libs/soundtouch/RateTransposer.cpp
index 740d099239..493d5326f2 100644
--- a/libs/soundtouch/RateTransposer.cpp
+++ b/libs/soundtouch/RateTransposer.cpp
@@ -339,7 +339,7 @@ void RateTransposer::clear()
// Returns nonzero if there aren't any samples available for outputting.
-uint RateTransposer::isEmpty()
+int RateTransposer::isEmpty() const
{
int res;
diff --git a/libs/soundtouch/RateTransposer.h b/libs/soundtouch/RateTransposer.h
index f7c03f759e..5315d6fec3 100644
--- a/libs/soundtouch/RateTransposer.h
+++ b/libs/soundtouch/RateTransposer.h
@@ -150,7 +150,7 @@ public:
void clear();
/// Returns nonzero if there aren't any samples available for outputting.
- uint isEmpty();
+ int isEmpty() const;
};
}
diff --git a/libs/soundtouch/TDStretch.cpp b/libs/soundtouch/TDStretch.cpp
index f1b85b5f17..c71c65967f 100644
--- a/libs/soundtouch/TDStretch.cpp
+++ b/libs/soundtouch/TDStretch.cpp
@@ -114,13 +114,6 @@ TDStretch::~TDStretch()
-// Calculates the x having the closest 2^x value for the given value
-static int _getClosest2Power(double value)
-{
- return (int)(log(value) / log(2.0) + 0.5);
-}
-
-
// Sets routine control parameters. These control are certain time constants
// defining how the sound is stretched to the desired duration.
diff --git a/libs/soundtouch/cpu_detect_x86_gcc.cpp b/libs/soundtouch/cpu_detect_x86_gcc.cpp
index b4ccdc2834..b58b80fa06 100644
--- a/libs/soundtouch/cpu_detect_x86_gcc.cpp
+++ b/libs/soundtouch/cpu_detect_x86_gcc.cpp
@@ -80,6 +80,7 @@ uint detectCPUextensions(void)
if (_dwDisabledISA == 0xffffffff) return 0;
asm volatile(
+ "\n\tpushl %%ebx" // store ebx
"\n\txor %%esi, %%esi" // clear %%esi = result register
// check if 'cpuid' instructions is available by toggling eflags bit 21
@@ -128,6 +129,7 @@ uint detectCPUextensions(void)
"\n\tend:"
"\n\tmov %%esi, %0"
+ "\n\tpopl %%ebx"
: "=r" (res)
: /* no inputs */
diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc
index e6642d3394..44445192be 100644
--- a/libs/surfaces/control_protocol/basic_ui.cc
+++ b/libs/surfaces/control_protocol/basic_ui.cc
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <pbd/pthread_utils.h>
diff --git a/libs/surfaces/control_protocol/control_protocol.cc b/libs/surfaces/control_protocol/control_protocol.cc
index d660c10800..1ef7a2c1b4 100644
--- a/libs/surfaces/control_protocol/control_protocol.cc
+++ b/libs/surfaces/control_protocol/control_protocol.cc
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <ardour/session.h>
diff --git a/libs/surfaces/control_protocol/control_protocol/basic_ui.h b/libs/surfaces/control_protocol/control_protocol/basic_ui.h
index 23b274ca01..7bc6b25c32 100644
--- a/libs/surfaces/control_protocol/control_protocol/basic_ui.h
+++ b/libs/surfaces/control_protocol/control_protocol/basic_ui.h
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_basic_ui_h__
diff --git a/libs/surfaces/control_protocol/control_protocol/control_protocol.h b/libs/surfaces/control_protocol/control_protocol/control_protocol.h
index a689d49431..c0961645ab 100644
--- a/libs/surfaces/control_protocol/control_protocol/control_protocol.h
+++ b/libs/surfaces/control_protocol/control_protocol/control_protocol.h
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef ardour_control_protocols_h
diff --git a/libs/surfaces/frontier/kernel_drivers/BUILD b/libs/surfaces/frontier/kernel_drivers/BUILD
new file mode 100644
index 0000000000..dc612e20bf
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/BUILD
@@ -0,0 +1,10 @@
+To build, type make
+
+# make install and run
+ir: install
+ rmmod tranzport
+ modprobe tranzport
+
+# make install, run, and run tests
+irt: ir
+
diff --git a/libs/surfaces/frontier/kernel_drivers/Makefile b/libs/surfaces/frontier/kernel_drivers/Makefile
new file mode 100644
index 0000000000..223fcdb6fc
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/Makefile
@@ -0,0 +1,35 @@
+ifneq ($(KERNELRELEASE),)
+
+obj-m := tranzport.o
+tranzport-objs :=
+
+else
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+MODDIR := $(DESTDIR)/lib/modules/$(shell uname -r)/kernel/sound/usb/misc
+BINDIR := $(DESTDIR)/usr/local/bin
+
+default::
+ $(MAKE) -Wall -C $(KDIR) SUBDIRS=$(PWD) modules
+ $(MAKE) -C tests
+
+install-only:: default
+ mkdir -p $(MODDIR) $(BINDIR)
+ cp tranzport.ko $(MODDIR)
+ $(MAKE) -C tests install
+
+install:: install-only
+ /sbin/depmod -a
+ +/sbin/rmmod tranzport
+ /sbin/modprobe tranzport
+
+irt:: install
+ tranzport_tests.sh
+
+clean::
+ rm -f core .*.cmd *.o *.ko *.mod.c Module.symvers *.bak .\#* *~
+ rm -rf .tmp_versions
+ $(MAKE) -C tests clean
+
+endif
diff --git a/libs/surfaces/frontier/kernel_drivers/README b/libs/surfaces/frontier/kernel_drivers/README
new file mode 100644
index 0000000000..51b4af0f2e
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/README
@@ -0,0 +1,16 @@
+This directory contains the USB Tranzport Kernel driver for Linux.
+
+At present it accepts reads/writes of 8 byte cmds to /dev/tranzport0 to control
+the lights and screen.
+
+Reads are possible. Wheel Compression does not currently account for button changes
+
+It also has some sysfs hooks that are non-functional at the moment.
+
+The API is closely tied to the ardour revision and WILL change.
+
+A sysfs interface is PERFECT for simple userspace apps to do fun things with the
+lights and screen. It's fairly lousy for handling input events and very lousy
+for watching the state of the shuttle wheel.
+
+In the end this is going to be driven by a midi layer
diff --git a/libs/surfaces/frontier/kernel_drivers/doc/keycodes.html b/libs/surfaces/frontier/kernel_drivers/doc/keycodes.html
new file mode 100644
index 0000000000..651517a7f2
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/doc/keycodes.html
@@ -0,0 +1,35 @@
+<HTML>
+<HEAD>
+<TITLE> TRANZPORT KEYCODES REFERENCE </TITLE>
+</HEAD>
+<BODY>
+<H2> TRANZPORT KEYCODES REFERENCE </H2>
+
+<H3>Footswitch</H3>
+
+At least on every footswitch I've tried, the polarity appears to be wrong, in that the footswitch "up" position results
+in 0100 being OR'd into the result. Pressing it down results in a 0, if no other keys are pressed. Releasing it results in 0100.
+
+Every other key when up results in 0. This odd behavior would hopefully be controllable via a command to the tranzport,
+but I don't have that, so dealing with footswitch events is weird.
+
+So, seeing this bit enabled would be something like "HAVE_FOOTSWITCH INSTALLED", BE SMART ABOUT IT.
+
+
+<H3>Special Key Combinations</H3>
+<p>
+In addition to the normal keycodes generated by the tranzport, it is possible to hit several combinations of keys and get a unique
+result. Some are really weird. Perhaps the following assignments make sense:
+</p><p>
+<table><tr><th>PRESSING</th><th>RESULT</th><th>ASSIGNED TO</th></tr>
+<tr><td>TRACKLEFT+TRACKRIGHT</td><td>TRACKLEFT+TRACKRIGHT</td><td>Master</td></tr>
+<tr><td>SHIFT+TRACKLEFT+TRACKRIGHT</td><td>SHIFT+TRACKLEFT+TRACKRIGHT+UNDO</td><td>Show Bus Only Toggle</td></tr>
+<tr><td>IN+OUT</td><td>IN+OUT</td><td>Zoom 100%</td></tr>
+<tr><td>SHIFT+IN+OUT</td><td>SHIFT+IN+OUT+UNDO</td><td>Max Zoom</td></tr>
+<tr><td>SHIFT+REW+FFW</td><td>SHIFT+REW+FFW+UNDO</td><td></td></tr>
+<tr><td>RECORD+TRACKSOLO+FOOTSWITCHNOTDEPRESSED</td><td>RECORD+TRACKSOLO+BATTERY</td><td></td></tr>
+<tr><td>PLAY+MUTE</td><td>PLAY+MUTE</td><td></td></tr>
+</table>
+</p>
+</body>
+</html>
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/Makefile b/libs/surfaces/frontier/kernel_drivers/tests/Makefile
new file mode 100644
index 0000000000..534bc7da4b
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/Makefile
@@ -0,0 +1,23 @@
+# Some basic utilities for testing the tranzport's I/O
+# eventually "tranzport" will become a flexible command
+#
+#
+
+FILES:=tranzport tranzport_lights tranzport_tests.sh
+BINDIR ?= $(DESTDIR)/usr/local/bin
+
+all: tranzport tranzport_lights
+
+tranzport: tranzport.c
+ gcc -g -Wall -o tranzport tranzport.c
+
+tranzport_lights: tranzport_lights.c
+ gcc -g -Wall -o tranzport_lights tranzport_lights.c
+
+clean::
+ rm -f core .*.cmd *.o *.ko *.mod.c Module.symvers *.bak .\#* *~
+ rm -rf .tmp_versions tranzport tranzport_lights
+
+install::
+ cp $(FILES) $(BINDIR)
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/README b/libs/surfaces/frontier/kernel_drivers/tests/README
new file mode 100644
index 0000000000..f9efd18f69
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/README
@@ -0,0 +1,104 @@
+tranzport 0.1 <tranzport.sf.net>
+oct 18, 2005
+arthur@artcmusic.com
+---
+
+The Frontier Design Tranzport(tm) (www.frontierdesign.com) is a simple
+wireless USB device. It is not a MIDI device. The document on their web
+site "Tranzport(tm) Native Mode Interface Description" describes the
+Tranzport(tm) as if it were a MIDI device, but this is implemented by their
+Windows and Macintosh software drivers.
+
+This code will allow you to use your Tranzport(tm) at a lower level of
+abstraction. This code relies on libusb, which can be obtained from
+libusb.sourceforge.net.
+
+To compile the program, type "make". You should end up with a executable
+called "tranzport". You'll probably have to run this program as root.
+
+Using the program is straightforward. It will simply tell you which
+buttons are being pressed and what not. If you press one of the buttons
+with a light, the light will turn on. If you hold shift and press one of
+the buttons with a light, the light will turn off. If you take out the
+batteries to the device (or go out of range), it will tell you that the
+device is offline. When you replace the batteries (or come back in
+range), it should tell you it is back online.
+
+Once you understand how everything works, you should be able to
+incorporate it into your own setup however you wish.
+
+This code was developed on a Linux machine, but (theoretically) it
+should work on any system that is supported by libusb, since that is how
+it communicates with the device.
+
+Here are a few more details about the device:
+
+There are two endpoints for communication with the device. All data
+reads and writes are done in 8-byte segments.
+
+One endpoint is for interrupt reads. This is used to read button data
+from the device. It also supplies status information for when the device
+goes out of range and comes back in range, loses power and regains
+power, etc. The format of the data is:
+
+ 00 ss bb bb bb bb dd 00 (hexadecimal)
+
+where:
+
+ ss - status code, 01=online ff=offline
+ bb - button bits
+ dd - data wheel, 01-3f=forward 41-7f=backward
+
+Please refer to the source code for a list of the button bits.
+
+The other endpoint is for interrupt writes. This is used to toggle the
+lights on the device, and to write data to the LCD.
+
+There are 7 lights on the device. To turn a light on, send the following
+sequence of bytes:
+
+ 00 00 nn 01 00 00 00 00 (hexadecimal)
+
+where nn is the light number.
+
+To turn a light off:
+
+ 00 00 nn 00 00 00 00 00 (hexadecimal)
+
+Here is the list of lights:
+
+ 00 Record
+ 01 Track Rec
+ 02 Track Mute
+ 03 Track Solo
+ 04 Any Solo
+ 05 Loop
+ 06 Punch
+
+The size of the LCD is 20x2, and it is split into 10 cells, each cell
+being 4 characters wide. The cells progress across, then down. To write
+to the LCD, send the following sequence of bytes:
+
+ 00 01 cc aa aa aa aa 00 (hexadecimal)
+
+where:
+
+ cc - cell number
+ aa - ASCII code
+
+Here is a list of the cells to clarify:
+
+ 00 row 0, column 0-3
+ 01 row 0, column 4-7
+ 02 row 0, column 8-11
+ 03 row 0, column 12-15
+ 04 row 0, column 16-19
+ 05 row 1, column 0-3
+ 06 row 1, column 4-7
+ 07 row 1, column 8-11
+ 08 row 1, column 12-15
+ 09 row 1, column 16-19
+
+You should refer to the "Tranzport(tm) Native Mode Interface
+Description" document for a listing of the ASCII codes the LCD uses.
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/tranzport.c b/libs/surfaces/frontier/kernel_drivers/tests/tranzport.c
new file mode 100644
index 0000000000..2ef5b6c910
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/tranzport.c
@@ -0,0 +1,375 @@
+/*
+ * tranzport 0.1 <tranzport.sf.net>
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+#define STATUS_OK 0x00
+
+struct tranzport_s {
+ int *dev;
+ int udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core()
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->udev = open("/dev/tranzport0",O_RDWR);
+ if (z->udev < 1)
+ die("unable to open tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+return open_tranzport_core();
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = close(z->udev);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = write(z->udev, cmd, 8);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0xff, 8);
+ val = read(z->udev, buf, 8);
+ if (val < 0) {
+ printf("errno: %d\n",errno);
+ switch(errno) {
+ case ENOENT: ;
+ case ECONNRESET: ;
+ case ESHUTDOWN: printf("dying\n"); exit(1); break;
+ }
+ return val;
+ }
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 10);
+ } else {
+ tranzport_lighton(z, light, 10);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons: %x ", buttons);
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 10);
+ tranzport_lcdwrite(z, 1, "DISL", 10);
+ tranzport_lcdwrite(z, 2, "EXIA", 10);
+ tranzport_lcdwrite(z, 3, " FOR", 10);
+ tranzport_lcdwrite(z, 4, " ", 10);
+
+ tranzport_lcdwrite(z, 5, " ", 10);
+ tranzport_lcdwrite(z, 6, " CUR", 10);
+ tranzport_lcdwrite(z, 7, "E FO", 10);
+ tranzport_lcdwrite(z, 8, "UND ", 10);
+ tranzport_lcdwrite(z, 9, " ", 10);
+}
+
+void do_lcd2(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, "THE ", 10);
+ tranzport_lcdwrite(z, 1, "TRAN", 10);
+ tranzport_lcdwrite(z, 2, "ZPOR", 10);
+ tranzport_lcdwrite(z, 3, "T RO", 10);
+ tranzport_lcdwrite(z, 4, " KS", 10);
+
+ tranzport_lcdwrite(z, 5, "AWES", 10);
+ tranzport_lcdwrite(z, 6, "OMEE", 10);
+ tranzport_lcdwrite(z, 7, "LEEE", 10);
+ tranzport_lcdwrite(z, 8, "UND ", 10);
+ tranzport_lcdwrite(z, 9, "GROK", 10);
+}
+
+int lights_off(tranzport_t *z) {
+ static int i = 0;
+ int j = 0;
+ for(;j<2; j++,i = (i+1) % 7) {
+ tranzport_lightoff(z, i, 10);
+ }
+return 0;
+}
+
+int lights_on(tranzport_t *z) {
+ static int i = 0;
+ int j = 0;
+ for(;j<2; j++,i = (i+1) % 7) {
+ tranzport_lighton(z, i, 10);
+ }
+return 0;
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+
+ // do_lcd(z);
+ lights_on(z);
+ // do_lcd2(z);
+
+ val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline: ");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online: ");
+ do_lcd(z);
+ }
+
+ if (status == STATUS_OK) {
+ printf("OK: ");
+ do_lcd(z);
+ }
+
+// do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ lights_off(z);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c
new file mode 100644
index 0000000000..4096ee680d
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c
@@ -0,0 +1,361 @@
+/*
+ * tranzport 0.1 <tranzport.sf.net>
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+#define STATUS_OK 0x00
+
+struct tranzport_s {
+ int *dev;
+ int udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core()
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->udev = open("/dev/tranzport0",O_RDWR);
+ if (!z->udev)
+ die("unable to open tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+return open_tranzport_core();
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = close(z->udev);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = write(z->udev, cmd, 8);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0xff, 8);
+ val = read(z->udev, buf, 8);
+ if (val < 0) {
+ // printf("errno: %d\n",errno);
+ return val;
+ }
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 1000);
+ } else {
+ tranzport_lighton(z, light, 1000);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons: %x ", buttons);
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 1000);
+ tranzport_lcdwrite(z, 1, "DISL", 1000);
+ tranzport_lcdwrite(z, 2, "EXIA", 1000);
+ tranzport_lcdwrite(z, 3, " FOR", 1000);
+ tranzport_lcdwrite(z, 4, " ", 1000);
+
+ tranzport_lcdwrite(z, 5, " ", 1000);
+ tranzport_lcdwrite(z, 6, " CUR", 1000);
+ tranzport_lcdwrite(z, 7, "E FO", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, " ", 1000);
+}
+
+void do_lcd2(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, "THE ", 1000);
+ tranzport_lcdwrite(z, 1, "TRAN", 1000);
+ tranzport_lcdwrite(z, 2, "ZPOR", 1000);
+ tranzport_lcdwrite(z, 3, "T RO", 1000);
+ tranzport_lcdwrite(z, 4, "KS ", 1000);
+
+ tranzport_lcdwrite(z, 5, "AWES", 1000);
+ tranzport_lcdwrite(z, 6, "OMEE", 1000);
+ tranzport_lcdwrite(z, 7, "LEEE", 1000);
+ tranzport_lcdwrite(z, 8, "WITH", 1000);
+ tranzport_lcdwrite(z, 9, "ARDO", 1000);
+}
+
+lights_off(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lightoff(z, i, 1000);
+ }
+}
+
+lights_on(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lighton(z, i, 1000);
+ }
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+
+ do_lcd(z);
+ lights_on(z);
+ do_lcd2(z);
+ lights_off(z);
+
+// val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ val = -1;
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline: ");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online: ");
+ do_lcd(z);
+ }
+
+ do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh
new file mode 100755
index 0000000000..540c62fe16
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+echo "Testing lights"
+tranzport_lights &
+A=$!
+sleep 30
+kill $A
+echo "Testing interleaved_reads/writes"
+tranzport &
+A=$!
+sleep 30
+kill $A
+
+exit 0
+
+# not done yet
+echo "Testing_screen"
+tranzport_screen &
+A=$!
+sleep 30
+kill $A
+echo "Testing_reads"
+tranzport_read &
+A=$!
+sleep 30
+kill $A
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tranzport.c b/libs/surfaces/frontier/kernel_drivers/tranzport.c
new file mode 100644
index 0000000000..6893f66921
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tranzport.c
@@ -0,0 +1,1065 @@
+/*
+ * Frontier Designs Tranzport driver
+ *
+ * Copyright (C) 2007 Michael Taht (m@taht.net)
+ *
+ * Based on the usbled driver and ldusb drivers by
+ *
+ * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de>
+ *
+ * The ldusb driver was, in turn, derived from Lego USB Tower driver
+ * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net>
+ * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net>
+ *
+ * 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, version 2.
+ *
+ */
+
+/**
+ * This driver uses a ring buffer for time critical reading of
+ * interrupt in reports and provides read and write methods for
+ * raw interrupt reports.
+ */
+
+/* Note: this currently uses a dumb ringbuffer for reads and writes.
+ * A more optimal driver would cache and kill off outstanding urbs that are
+ * now invalid, and ignore ones that already were in the queue but valid
+ * as we only have 17 commands for the tranzport. In particular this is
+ * key for getting lights to flash in time as otherwise many commands
+ * can be buffered up before the light change makes it to the interface.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/version.h>
+
+#include <asm/uaccess.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+
+/* Define these values to match your devices */
+#define VENDOR_ID 0x165b
+#define PRODUCT_ID 0x8101
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define USB_TRANZPORT_MINOR_BASE 0
+#else
+// FIXME 176 - is the ldusb driver's minor - apply for that
+#define USB_TRANZPORT_MINOR_BASE 176
+#endif
+
+/* table of devices that work with this driver */
+static struct usb_device_id usb_tranzport_table [] = {
+ { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usb_tranzport_table);
+MODULE_VERSION("0.29");
+MODULE_AUTHOR("Mike Taht <m@taht.net>");
+MODULE_DESCRIPTION("Tranzport USB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Frontier Designs Control Surface");
+
+
+/* make this work on older kernel versions */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+
+/**
+ * usb_endpoint_dir_out - check if the endpoint has OUT direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type OUT, otherwise it returns false.
+ */
+
+static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+}
+
+static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
+}
+
+
+/**
+ * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type interrupt, otherwise it returns
+ * false.
+ */
+static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT);
+}
+
+
+/**
+ * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and IN direction,
+ * otherwise it returns false.
+ */
+
+static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+
+static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
+}
+
+#endif /* older kernel versions */
+
+/* These two aren't done yet */
+
+#define SUPPRESS_EXTRA_ONLINE_EVENTS 0
+#define BUFFERED_WRITES 0
+
+#define SUPPRESS_EXTRA_OFFLINE_EVENTS 1
+#define COMPRESS_WHEEL_EVENTS 1
+#define BUFFERED_READS 1
+#define RING_BUFFER_SIZE 1000
+#define WRITE_BUFFER_SIZE 34
+#define TRANZPORT_USB_TIMEOUT 10
+
+
+static int debug = 0;
+
+/* Use our own dbg macro */
+#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+/* Module parameters */
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* All interrupt in transfers are collected in a ring buffer to
+ * avoid racing conditions and get better performance of the driver.
+ */
+
+static int ring_buffer_size = RING_BUFFER_SIZE;
+
+module_param(ring_buffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports");
+
+/* The write_buffer can one day contain more than one interrupt out transfer.
+ */
+static int write_buffer_size = WRITE_BUFFER_SIZE;
+module_param(write_buffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
+
+/*
+ * Increase the interval for debugging purposes.
+ * or set to 1 to use the standard interval from the endpoint descriptors.
+ */
+
+static int min_interrupt_in_interval = TRANZPORT_USB_TIMEOUT;
+module_param(min_interrupt_in_interval, int, 0);
+MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms");
+
+static int min_interrupt_out_interval = TRANZPORT_USB_TIMEOUT;
+module_param(min_interrupt_out_interval, int, 0);
+MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms");
+
+struct tranzport_cmd {
+ unsigned char cmd[8];
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_tranzport {
+ struct semaphore sem; /* locks this structure */
+ struct usb_interface* intf; /* save off the usb interface pointer */
+
+ int open_count; /* number of times this port has been opened */
+
+ struct tranzport_cmd (*ring_buffer)[RING_BUFFER_SIZE]; /* just make c happy */
+ unsigned int ring_head;
+ unsigned int ring_tail;
+
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ unsigned char* interrupt_in_buffer;
+ struct usb_endpoint_descriptor* interrupt_in_endpoint;
+ struct urb* interrupt_in_urb;
+ int interrupt_in_interval;
+ size_t interrupt_in_endpoint_size;
+ int interrupt_in_running;
+ int interrupt_in_done;
+
+ char* interrupt_out_buffer;
+ struct usb_endpoint_descriptor* interrupt_out_endpoint;
+ struct urb* interrupt_out_urb;
+ int interrupt_out_interval;
+ size_t interrupt_out_endpoint_size;
+ int interrupt_out_busy;
+
+ /* Sysfs support - most of these are not hooked up yet */
+
+ int event; /* alternate interface to events */
+ int wheel; /* - for negative, 0 for none, + for positive */
+ int lights;
+ unsigned char dump_state; /* 0 if disabled 1 if enabled */
+ unsigned char enable; /* 0 if disabled 1 if enabled */
+ unsigned char offline; /* if the device is out of range or asleep */
+ unsigned char compress_wheel; /* flag to compress wheel events */
+ unsigned char LightRecord;
+ unsigned char LightTrackrec;
+ unsigned char LightTrackmute;
+ unsigned char LightTracksolo;
+ unsigned char LightAnysolo;
+ unsigned char LightLoop;
+ unsigned char LightPunch;
+ unsigned char last_cmd[8];
+ unsigned char screen[40]; // We'll also have cells
+
+};
+
+/* prevent races between open() and disconnect() */
+static DEFINE_MUTEX(disconnect_mutex);
+
+static struct usb_driver usb_tranzport_driver;
+
+/**
+ * usb_tranzport_abort_transfers
+ * aborts transfers and frees associated data structures
+ */
+static void usb_tranzport_abort_transfers(struct usb_tranzport *dev)
+{
+ /* shutdown transfer */
+ if (dev->interrupt_in_running) {
+ dev->interrupt_in_running = 0;
+ if (dev->intf)
+ usb_kill_urb(dev->interrupt_in_urb);
+ }
+ if (dev->interrupt_out_busy)
+ if (dev->intf)
+ usb_kill_urb(dev->interrupt_out_urb);
+}
+
+#define show_set_light(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", t->value); \
+} \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ int temp = simple_strtoul(buf, NULL, 10); \
+ \
+ t->value = temp; \
+ return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+
+show_set_light(LightRecord);
+show_set_light(LightTrackrec);
+show_set_light(LightTrackmute);
+show_set_light(LightTracksolo);
+show_set_light(LightAnysolo);
+show_set_light(LightLoop);
+show_set_light(LightPunch);
+
+show_set_light(enable);
+show_set_light(offline);
+show_set_light(compress_wheel);
+show_set_light(dump_state);
+
+#define show_set_int(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", t->value); \
+} \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ int temp = simple_strtoul(buf, NULL, 10); \
+ \
+ t->value = temp; \
+ return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+
+show_set_int(wheel);
+show_set_int(event);
+
+#define show_set_cmd(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", t->value); \
+} \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ int temp = simple_strtoul(buf, NULL, 10); \
+ \
+ t->value = temp; \
+ return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+
+
+
+
+/**
+ * usb_tranzport_delete
+ */
+static void usb_tranzport_delete(struct usb_tranzport *dev)
+{
+ usb_tranzport_abort_transfers(dev);
+ /* This is just too twisted to be correct */
+ if(dev->intf != NULL) {
+ device_remove_file(&dev->intf->dev, &dev_attr_LightRecord);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTrackrec);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTrackmute);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTracksolo);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTrackmute);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightAnysolo);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightLoop);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightPunch);
+ device_remove_file(&dev->intf->dev, &dev_attr_wheel);
+ device_remove_file(&dev->intf->dev, &dev_attr_enable);
+ device_remove_file(&dev->intf->dev, &dev_attr_event);
+ device_remove_file(&dev->intf->dev, &dev_attr_offline);
+ device_remove_file(&dev->intf->dev, &dev_attr_compress_wheel);
+
+ device_remove_file(&dev->intf->dev, &dev_attr_dump_state);
+ }
+
+ /* free data structures */
+ usb_free_urb(dev->interrupt_in_urb);
+ usb_free_urb(dev->interrupt_out_urb);
+ kfree(dev->ring_buffer);
+ kfree(dev->interrupt_in_buffer);
+ kfree(dev->interrupt_out_buffer);
+ kfree(dev);
+}
+
+/**
+ * usb_tranzport_interrupt_in_callback
+ */
+
+static void usb_tranzport_interrupt_in_callback(struct urb *urb)
+{
+ struct usb_tranzport *dev = urb->context;
+ unsigned int next_ring_head;
+ int retval = -1;
+
+ if (urb->status) {
+ if (urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN) {
+ goto exit;
+ } else {
+ dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
+ __FUNCTION__, urb->status);
+ goto resubmit; /* maybe we can recover */
+ }
+ }
+
+ if (urb->actual_length != 8) {
+ dev_warn(&dev->intf->dev,
+ "Urb length was %d bytes!! Do something intelligent \n", urb->actual_length);
+ } else {
+ dbg_info(&dev->intf->dev, "%s: received: %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __FUNCTION__, dev->interrupt_in_buffer[0],dev->interrupt_in_buffer[1],dev->interrupt_in_buffer[2],dev->interrupt_in_buffer[3],dev->interrupt_in_buffer[4],dev->interrupt_in_buffer[5],dev->interrupt_in_buffer[6],dev->interrupt_in_buffer[7]);
+#if SUPPRESS_EXTRA_OFFLINE_EVENTS
+ if(dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) { goto resubmit; }
+ if(dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; }
+
+/* Always pass one offline event up the stack */
+ if(dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) { dev->offline = 0; }
+ if(dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 1; }
+
+#endif
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+
+ next_ring_head = (dev->ring_head+1) % ring_buffer_size;
+
+ if (next_ring_head != dev->ring_tail) {
+ memcpy(&((*dev->ring_buffer)[dev->ring_head]), dev->interrupt_in_buffer, urb->actual_length);
+ dev->ring_head = next_ring_head;
+ retval = 0;
+ memset(dev->interrupt_in_buffer, 0, urb->actual_length);
+ } else {
+ dev_warn(&dev->intf->dev,
+ "Ring buffer overflow, %d bytes dropped\n",
+ urb->actual_length);
+ memset(dev->interrupt_in_buffer, 0, urb->actual_length);
+ }
+ }
+
+resubmit:
+ /* resubmit if we're still running */
+ if (dev->interrupt_in_running && dev->intf) {
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&dev->intf->dev,
+ "usb_submit_urb failed (%d)\n", retval);
+ }
+
+exit:
+ dev->interrupt_in_done = 1;
+ wake_up_interruptible(&dev->read_wait);
+}
+
+/**
+ * usb_tranzport_interrupt_out_callback
+ */
+static void usb_tranzport_interrupt_out_callback(struct urb *urb)
+{
+ struct usb_tranzport *dev = urb->context;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status && !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ dbg_info(&dev->intf->dev,
+ "%s - nonzero write interrupt status received: %d\n",
+ __FUNCTION__, urb->status);
+
+ dev->interrupt_out_busy = 0;
+ wake_up_interruptible(&dev->write_wait);
+}
+
+/**
+ * usb_tranzport_open
+ */
+static int usb_tranzport_open(struct inode *inode, struct file *file)
+{
+ struct usb_tranzport *dev;
+ int subminor;
+ int retval = 0;
+ struct usb_interface *interface;
+
+ nonseekable_open(inode, file);
+ subminor = iminor(inode);
+
+ mutex_lock(&disconnect_mutex);
+
+ interface = usb_find_interface(&usb_tranzport_driver, subminor);
+
+ if (!interface) {
+ err("%s - error, can't find device for minor %d\n",
+ __FUNCTION__, subminor);
+ retval = -ENODEV;
+ goto unlock_disconnect_exit;
+ }
+
+ dev = usb_get_intfdata(interface);
+
+ if (!dev) {
+ retval = -ENODEV;
+ goto unlock_disconnect_exit;
+ }
+
+ /* lock this device */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto unlock_disconnect_exit;
+ }
+
+ /* allow opening only once */
+ if (dev->open_count) {
+ retval = -EBUSY;
+ goto unlock_exit;
+ }
+ dev->open_count = 1;
+
+ /* initialize in direction */
+ dev->ring_head = 0;
+ dev->ring_tail = 0;
+ usb_fill_int_urb(dev->interrupt_in_urb,
+ interface_to_usbdev(interface),
+ usb_rcvintpipe(interface_to_usbdev(interface),
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ dev->interrupt_in_endpoint_size,
+ usb_tranzport_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_interval);
+
+ dev->interrupt_in_running = 1;
+ dev->interrupt_in_done = 0;
+ dev->enable = 1;
+ dev->offline = 0;
+ dev->compress_wheel = 1;
+
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval);
+ dev->interrupt_in_running = 0;
+ dev->open_count = 0;
+ goto unlock_exit;
+ }
+
+ /* save device in the file's private structure */
+ file->private_data = dev;
+
+
+unlock_exit:
+ up(&dev->sem);
+
+unlock_disconnect_exit:
+ mutex_unlock(&disconnect_mutex);
+
+ return retval;
+}
+
+/**
+ * usb_tranzport_release
+ */
+static int usb_tranzport_release(struct inode *inode, struct file *file)
+{
+ struct usb_tranzport *dev;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ if (dev == NULL) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ if (dev->open_count != 1) {
+ retval = -ENODEV;
+ goto unlock_exit;
+ }
+
+ if (dev->intf == NULL) {
+ /* the device was unplugged before the file was released */
+ up(&dev->sem);
+ /* unlock here as usb_tranzport_delete frees dev */
+ usb_tranzport_delete(dev);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* wait until write transfer is finished */
+ if (dev->interrupt_out_busy)
+ wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
+ usb_tranzport_abort_transfers(dev);
+ dev->open_count = 0;
+
+unlock_exit:
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/**
+ * usb_tranzport_poll
+ */
+static unsigned int usb_tranzport_poll(struct file *file, poll_table *wait)
+{
+ struct usb_tranzport *dev;
+ unsigned int mask = 0;
+
+ dev = file->private_data;
+
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+ if (dev->ring_head != dev->ring_tail)
+ mask |= POLLIN | POLLRDNORM;
+ if (!dev->interrupt_out_busy)
+ mask |= POLLOUT | POLLWRNORM;
+
+ return mask;
+}
+
+/**
+ * usb_tranzport_read
+ */
+static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct usb_tranzport *dev;
+ size_t bytes_to_read;
+ int retval = 0;
+
+#if BUFFERED_READS
+ int c = 0;
+#endif
+
+#if COMPRESS_WHEEL_EVENTS
+ signed char oldwheel;
+ signed char newwheel;
+ int cancompress = 1;
+ int next_tail;
+#endif
+
+/* do I have such a thing as a null event? */
+
+ dev = file->private_data;
+
+ /* verify that we actually have some data to read */
+ if (count == 0)
+ goto exit;
+
+ /* lock this object */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d\n", retval);
+ goto unlock_exit;
+ }
+
+ while (dev->ring_head == dev->ring_tail) {
+
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ // atomic_cmp_exchange(&dev->interrupt_in_done,0,0);
+ dev->interrupt_in_done = 0 ; /* tiny race - FIXME: make atomic? */
+ retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
+ if (retval < 0) {
+ goto unlock_exit;
+ }
+ }
+
+ dbg_info(&dev->intf->dev, "%s: copying to userspace: %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+
+#if BUFFERED_READS
+ c = 0;
+ while((c < count) && (dev->ring_tail != dev->ring_head)) {
+
+/* This started off in the lower level service routine, and I moved it here. Then my brain died. Not done yet. */
+#if COMPRESS_WHEEL_EVENTS
+ next_tail = (dev->ring_tail+1) % ring_buffer_size;
+ if(dev->compress_wheel) cancompress = 1;
+ while(dev->ring_head != next_tail && cancompress == 1 ) {
+ newwheel = (*dev->ring_buffer)[next_tail].cmd[6];
+ oldwheel = (*dev->ring_buffer)[dev->ring_tail].cmd[6];
+ // if both are wheel events, and no buttons have changes (FIXME, do I have to check?),
+ // and we are the same sign, we can compress +- 7F
+ // FIXME: saner check for overflow! - max of +- 7F
+ // FIXME the math is wrong for going in reverse, actually, as the midi spec doesn't allow signed chars
+
+ dbg_info(&dev->intf->dev, "%s: trying to compress: %02x%02x%02x%02x%02x %02x %02x %02x\n",
+ __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+
+
+ if(((*dev->ring_buffer)[dev->ring_tail].cmd[6] != 0 &&
+ (*dev->ring_buffer)[next_tail].cmd[6] != 0 ) &&
+ ((newwheel > 0 && oldwheel > 0) ||
+ (newwheel < 0 && oldwheel < 0)) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[2] == (*dev->ring_buffer)[next_tail].cmd[2]) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[3] == (*dev->ring_buffer)[next_tail].cmd[3]) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[4] == (*dev->ring_buffer)[next_tail].cmd[4]) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[5] == (*dev->ring_buffer)[next_tail].cmd[5]))
+ {
+ dbg_info(&dev->intf->dev, "%s: should compress: %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+
+ newwheel += oldwheel;
+ if(oldwheel > 0 && !(newwheel > 0)) {
+ newwheel = 0x7f;
+ cancompress = 0;
+ }
+ if(oldwheel < 0 && !(newwheel < 0)) {
+ newwheel = 0x80;
+ cancompress = 0;
+ }
+
+ (*dev->ring_buffer)[next_tail].cmd[6] = newwheel;
+ dev->ring_tail = next_tail;
+ next_tail = (dev->ring_tail+1) % ring_buffer_size;
+ } else {
+ cancompress = 0;
+ }
+ }
+#endif /* COMPRESS_WHEEL_EVENTS */
+
+ if (copy_to_user(&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], 8)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
+ c+=8;
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ }
+ retval = c;
+
+#else
+ if (copy_to_user(buffer, &(*dev->ring_buffer)[dev->ring_tail], 8)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+
+ retval = 8;
+#endif /* BUFFERED_READS */
+
+unlock_exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/**
+ * usb_tranzport_write
+ */
+static ssize_t usb_tranzport_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct usb_tranzport *dev;
+ size_t bytes_to_write;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ /* verify that we actually have some data to write */
+ if (count == 0)
+ goto exit;
+
+ /* lock this object */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d\n", retval);
+ goto unlock_exit;
+ }
+
+ /* wait until previous transfer is finished */
+ if (dev->interrupt_out_busy) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy);
+ if (retval < 0) {
+ goto unlock_exit;
+ }
+ }
+
+ /* write the data into interrupt_out_buffer from userspace */
+ bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
+ if (bytes_to_write < count)
+ dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
+
+ dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
+
+ if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ if (dev->interrupt_out_endpoint == NULL) {
+ err("Endpoint should not be be null! \n");
+ goto unlock_exit;
+ }
+
+ /* send off the urb */
+ usb_fill_int_urb(dev->interrupt_out_urb,
+ interface_to_usbdev(dev->intf),
+ usb_sndintpipe(interface_to_usbdev(dev->intf),
+ dev->interrupt_out_endpoint->bEndpointAddress),
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ usb_tranzport_interrupt_out_callback,
+ dev,
+ dev->interrupt_out_interval);
+
+ dev->interrupt_out_busy = 1;
+ wmb();
+
+ retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
+ if (retval) {
+ dev->interrupt_out_busy = 0;
+ err("Couldn't submit interrupt_out_urb %d\n", retval);
+ goto unlock_exit;
+ }
+ retval = bytes_to_write;
+
+unlock_exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/* file operations needed when we register this driver */
+static const struct file_operations usb_tranzport_fops = {
+ .owner = THIS_MODULE,
+ .read = usb_tranzport_read,
+ .write = usb_tranzport_write,
+ .open = usb_tranzport_open,
+ .release = usb_tranzport_release,
+ .poll = usb_tranzport_poll,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with the driver core
+ */
+static struct usb_class_driver usb_tranzport_class = {
+ .name = "tranzport%d",
+ .fops = &usb_tranzport_fops,
+ .minor_base = USB_TRANZPORT_MINOR_BASE,
+};
+
+
+/**
+ * usb_tranzport_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int usb_tranzport_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_tranzport *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ int true_size;
+ int retval = -ENOMEM;
+
+ /* allocate memory for our device state and intialize it */
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&intf->dev, "Out of memory\n");
+ goto exit;
+ }
+ init_MUTEX(&dev->sem);
+ dev->intf = intf;
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+
+ iface_desc = intf->cur_altsetting;
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint))
+ dev->interrupt_in_endpoint = endpoint;
+
+ if (usb_endpoint_is_int_out(endpoint))
+ dev->interrupt_out_endpoint = endpoint;
+ }
+ if (dev->interrupt_in_endpoint == NULL) {
+ dev_err(&intf->dev, "Interrupt in endpoint not found\n");
+ goto error;
+ }
+ if (dev->interrupt_out_endpoint == NULL)
+ dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
+
+
+ dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+
+ if (dev->interrupt_in_endpoint_size != 8)
+ dev_warn(&intf->dev, "Interrupt in endpoint size is not 8!\n");
+
+ if(ring_buffer_size == 0) { ring_buffer_size = RING_BUFFER_SIZE; }
+ true_size = min(ring_buffer_size,RING_BUFFER_SIZE);
+ /* FIXME - there are more usb_alloc routines for dma correctness. Needed? */
+
+ dev->ring_buffer = kmalloc((true_size*sizeof(struct tranzport_cmd))+8, GFP_KERNEL);
+
+ if (!dev->ring_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate ring_buffer of size %d\n",true_size);
+ goto error;
+ }
+ dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
+ if (!dev->interrupt_in_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n");
+ goto error;
+ }
+ dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_in_urb) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
+ udev->descriptor.bMaxPacketSize0;
+
+ if (dev->interrupt_out_endpoint_size !=8)
+ dev_warn(&intf->dev, "Interrupt out endpoint size is not 8!)\n");
+
+ dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
+ if (!dev->interrupt_out_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n");
+ goto error;
+ }
+ dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_out_urb) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n");
+ goto error;
+ }
+ dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
+ if (dev->interrupt_out_endpoint)
+ dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(intf, dev);
+
+ retval = usb_register_dev(intf, &usb_tranzport_class);
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&intf->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(intf, NULL);
+ goto error;
+ }
+
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightRecord))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackrec))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackmute))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightTracksolo))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightAnysolo))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightLoop))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightPunch))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_wheel))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_event))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_dump_state))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_compress_wheel))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_enable))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_offline))) goto error;
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&intf->dev, "Tranzport Device #%d now attached to major %d minor %d\n",
+ (intf->minor - USB_TRANZPORT_MINOR_BASE), USB_MAJOR, intf->minor);
+
+exit:
+ return retval;
+
+error:
+ usb_tranzport_delete(dev);
+
+ return retval;
+}
+
+/**
+ * usb_tranzport_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void usb_tranzport_disconnect(struct usb_interface *intf)
+{
+ struct usb_tranzport *dev;
+ int minor;
+
+ /* FIXME: The skel code calls lock_kernel here, doesn't use a mutex, needed? */
+ mutex_lock(&disconnect_mutex);
+
+ dev = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ down(&dev->sem);
+
+ minor = intf->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(intf, &usb_tranzport_class);
+
+ /* if the device is not opened, then we clean up right now */
+ if (!dev->open_count) {
+ up(&dev->sem);
+ usb_tranzport_delete(dev);
+ } else {
+ dev->intf = NULL;
+ up(&dev->sem);
+ }
+
+ mutex_unlock(&disconnect_mutex);
+
+ dev_info(&intf->dev, "Tranzport Surface #%d now disconnected\n",
+ (minor - USB_TRANZPORT_MINOR_BASE));
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver usb_tranzport_driver = {
+ .name = "tranzport",
+ .probe = usb_tranzport_probe,
+ .disconnect = usb_tranzport_disconnect,
+ .id_table = usb_tranzport_table,
+};
+
+/**
+ * usb_tranzport_init
+ */
+static int __init usb_tranzport_init(void)
+{
+ int retval;
+
+ /* register this driver with the USB subsystem */
+ retval = usb_register(&usb_tranzport_driver);
+ if (retval)
+ err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
+
+ return retval;
+}
+
+/**
+ * usb_tranzport_exit
+ */
+static void __exit usb_tranzport_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&usb_tranzport_driver);
+}
+
+module_init(usb_tranzport_init);
+module_exit(usb_tranzport_exit);
+
diff --git a/libs/surfaces/frontier/tests/Makefile b/libs/surfaces/frontier/tests/Makefile
new file mode 100644
index 0000000000..aafb9aaa57
--- /dev/null
+++ b/libs/surfaces/frontier/tests/Makefile
@@ -0,0 +1,17 @@
+# Some basic utilities for testing the tranzport's I/O
+# eventually "tranzport" will become a flexible command
+#
+#
+all: tranzport tranzport_lights
+
+tranzport: tranzport.c
+ gcc -g -Wall -o tranzport tranzport.c
+
+tranzport_lights: tranzport_lights.c
+ gcc -g -Wall -o tranzport_lights tranzport_lights.c
+
+clean::
+ rm -f core .*.cmd *.o *.ko *.mod.c Module.symvers *.bak .\#* *~
+ rm -rf .tmp_versions tranzport tranzport_lights
+
+
diff --git a/libs/surfaces/frontier/tests/README b/libs/surfaces/frontier/tests/README
new file mode 100644
index 0000000000..f9efd18f69
--- /dev/null
+++ b/libs/surfaces/frontier/tests/README
@@ -0,0 +1,104 @@
+tranzport 0.1 <tranzport.sf.net>
+oct 18, 2005
+arthur@artcmusic.com
+---
+
+The Frontier Design Tranzport(tm) (www.frontierdesign.com) is a simple
+wireless USB device. It is not a MIDI device. The document on their web
+site "Tranzport(tm) Native Mode Interface Description" describes the
+Tranzport(tm) as if it were a MIDI device, but this is implemented by their
+Windows and Macintosh software drivers.
+
+This code will allow you to use your Tranzport(tm) at a lower level of
+abstraction. This code relies on libusb, which can be obtained from
+libusb.sourceforge.net.
+
+To compile the program, type "make". You should end up with a executable
+called "tranzport". You'll probably have to run this program as root.
+
+Using the program is straightforward. It will simply tell you which
+buttons are being pressed and what not. If you press one of the buttons
+with a light, the light will turn on. If you hold shift and press one of
+the buttons with a light, the light will turn off. If you take out the
+batteries to the device (or go out of range), it will tell you that the
+device is offline. When you replace the batteries (or come back in
+range), it should tell you it is back online.
+
+Once you understand how everything works, you should be able to
+incorporate it into your own setup however you wish.
+
+This code was developed on a Linux machine, but (theoretically) it
+should work on any system that is supported by libusb, since that is how
+it communicates with the device.
+
+Here are a few more details about the device:
+
+There are two endpoints for communication with the device. All data
+reads and writes are done in 8-byte segments.
+
+One endpoint is for interrupt reads. This is used to read button data
+from the device. It also supplies status information for when the device
+goes out of range and comes back in range, loses power and regains
+power, etc. The format of the data is:
+
+ 00 ss bb bb bb bb dd 00 (hexadecimal)
+
+where:
+
+ ss - status code, 01=online ff=offline
+ bb - button bits
+ dd - data wheel, 01-3f=forward 41-7f=backward
+
+Please refer to the source code for a list of the button bits.
+
+The other endpoint is for interrupt writes. This is used to toggle the
+lights on the device, and to write data to the LCD.
+
+There are 7 lights on the device. To turn a light on, send the following
+sequence of bytes:
+
+ 00 00 nn 01 00 00 00 00 (hexadecimal)
+
+where nn is the light number.
+
+To turn a light off:
+
+ 00 00 nn 00 00 00 00 00 (hexadecimal)
+
+Here is the list of lights:
+
+ 00 Record
+ 01 Track Rec
+ 02 Track Mute
+ 03 Track Solo
+ 04 Any Solo
+ 05 Loop
+ 06 Punch
+
+The size of the LCD is 20x2, and it is split into 10 cells, each cell
+being 4 characters wide. The cells progress across, then down. To write
+to the LCD, send the following sequence of bytes:
+
+ 00 01 cc aa aa aa aa 00 (hexadecimal)
+
+where:
+
+ cc - cell number
+ aa - ASCII code
+
+Here is a list of the cells to clarify:
+
+ 00 row 0, column 0-3
+ 01 row 0, column 4-7
+ 02 row 0, column 8-11
+ 03 row 0, column 12-15
+ 04 row 0, column 16-19
+ 05 row 1, column 0-3
+ 06 row 1, column 4-7
+ 07 row 1, column 8-11
+ 08 row 1, column 12-15
+ 09 row 1, column 16-19
+
+You should refer to the "Tranzport(tm) Native Mode Interface
+Description" document for a listing of the ASCII codes the LCD uses.
+
diff --git a/libs/surfaces/frontier/tests/tranzport.c b/libs/surfaces/frontier/tests/tranzport.c
new file mode 100644
index 0000000000..1eeacd6578
--- /dev/null
+++ b/libs/surfaces/frontier/tests/tranzport.c
@@ -0,0 +1,347 @@
+/*
+ * tranzport 0.1 <tranzport.sf.net>
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <usb.h>
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+
+struct tranzport_s {
+ struct usb_device *dev;
+ usb_dev_handle *udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core(struct usb_device *dev)
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->dev = dev;
+ z->udev = usb_open(z->dev);
+ if (!z->udev)
+ die("unable to open tranzport");
+
+ val = usb_claim_interface(z->udev, 0);
+ if (val < 0)
+ die("unable to claim tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for(bus=usb_busses; bus; bus=bus->next) {
+ for(dev=bus->devices; dev; dev=dev->next) {
+ if (dev->descriptor.idVendor != VENDORID)
+ continue;
+ if (dev->descriptor.idProduct != PRODUCTID)
+ continue;
+
+ return open_tranzport_core(dev);
+ }
+ }
+
+ die("can't find tranzport");
+ return 0;
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = usb_release_interface(z->udev, 0);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ val = usb_close(z->udev);
+ if (val < 0)
+ log_error("unable to close tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = usb_interrupt_write(z->udev, WRITE_ENDPOINT, cmd, 8, timeout);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0, 8);
+ val = usb_interrupt_read(z->udev, READ_ENDPOINT, buf, 8, timeout);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 1000);
+ } else {
+ tranzport_lighton(z, light, 1000);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons:");
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 1000);
+ tranzport_lcdwrite(z, 1, "DISL", 1000);
+ tranzport_lcdwrite(z, 2, "EXIA", 1000);
+ tranzport_lcdwrite(z, 3, " FOR", 1000);
+ tranzport_lcdwrite(z, 4, " ", 1000);
+
+ tranzport_lcdwrite(z, 5, " ", 1000);
+ tranzport_lcdwrite(z, 6, " CUR", 1000);
+ tranzport_lcdwrite(z, 7, "E FO", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, " ", 1000);
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+ val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline\n");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online\n");
+ do_lcd(z);
+ }
+
+ do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/tests/tranzport_lights.c b/libs/surfaces/frontier/tests/tranzport_lights.c
new file mode 100644
index 0000000000..28a8462d84
--- /dev/null
+++ b/libs/surfaces/frontier/tests/tranzport_lights.c
@@ -0,0 +1,361 @@
+/*
+ * tranzport 0.1 <tranzport.sf.net>
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+#define STATUS_OK 0x00
+
+struct tranzport_s {
+ int *dev;
+ int udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core()
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->udev = open("/dev/tranzport0",O_RDWR);
+ if (!z->udev)
+ die("unable to open tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+return open_tranzport_core();
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = close(z->udev);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = write(z->udev, cmd, 8);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0xff, 8);
+ val = read(z->udev, buf, 8);
+ if (val < 0) {
+ // printf("errno: %d\n",errno);
+ return val;
+ }
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 1000);
+ } else {
+ tranzport_lighton(z, light, 1000);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons: %x ", buttons);
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 1000);
+ tranzport_lcdwrite(z, 1, "DISL", 1000);
+ tranzport_lcdwrite(z, 2, "EXIA", 1000);
+ tranzport_lcdwrite(z, 3, " FOR", 1000);
+ tranzport_lcdwrite(z, 4, " ", 1000);
+
+ tranzport_lcdwrite(z, 5, " ", 1000);
+ tranzport_lcdwrite(z, 6, " CUR", 1000);
+ tranzport_lcdwrite(z, 7, "E FO", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, " ", 1000);
+}
+
+void do_lcd2(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, "THE ", 1000);
+ tranzport_lcdwrite(z, 1, "TRAN", 1000);
+ tranzport_lcdwrite(z, 2, "ZPOR", 1000);
+ tranzport_lcdwrite(z, 3, "T RO", 1000);
+ tranzport_lcdwrite(z, 4, " KS", 1000);
+
+ tranzport_lcdwrite(z, 5, "AWES", 1000);
+ tranzport_lcdwrite(z, 6, "OMEE", 1000);
+ tranzport_lcdwrite(z, 7, "LEEE", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, "GROK", 1000);
+}
+
+lights_off(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lightoff(z, i, 1000);
+ }
+}
+
+lights_on(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lighton(z, i, 1000);
+ }
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+
+ do_lcd(z);
+ lights_on(z);
+ do_lcd2(z);
+ lights_off(z);
+
+// val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ val = -1;
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline: ");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online: ");
+ do_lcd(z);
+ }
+
+ do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/tranzport/SConscript b/libs/surfaces/frontier/tranzport/SConscript
new file mode 100644
index 0000000000..5d390f3e2f
--- /dev/null
+++ b/libs/surfaces/frontier/tranzport/SConscript
@@ -0,0 +1,56 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+tranzport = env.Copy()
+
+#
+# this defines the version number of libardour_tranzport
+#
+
+domain = 'ardour_tranzport'
+
+tranzport.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+tranzport.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+tranzport.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+tranzport.Append(PACKAGE = domain)
+tranzport.Append(POTFILE = domain + '.pot')
+
+tranzport_files=Split("""
+interface.cc
+tranzport_control_protocol.cc
+""")
+
+tranzport.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+tranzport.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+tranzport.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+tranzport.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+tranzport.Merge ([
+ libraries['ardour'],
+ libraries['ardour_cp'],
+ libraries['sigc2'],
+ libraries['pbd'],
+ libraries['midi++2'],
+ libraries['xml'],
+ libraries['usb'],
+ libraries['glib2'],
+ libraries['glibmm2']
+ ])
+
+libardour_tranzport = tranzport.SharedLibrary('ardour_tranzport', tranzport_files)
+
+if tranzport['TRANZPORT']:
+ Default(libardour_tranzport)
+ if env['NLS']:
+ i18n (tranzport, tranzport_files, env)
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_tranzport))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript' ] +
+ tranzport_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/frontier/tranzport/interface.cc b/libs/surfaces/frontier/tranzport/interface.cc
new file mode 100644
index 0000000000..f6d0dc8206
--- /dev/null
+++ b/libs/surfaces/frontier/tranzport/interface.cc
@@ -0,0 +1,51 @@
+#include <control_protocol/control_protocol.h>
+#include "tranzport_control_protocol.h"
+
+using namespace ARDOUR;
+
+ControlProtocol*
+new_tranzport_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ TranzportControlProtocol* tcp = new TranzportControlProtocol (*s);
+
+ if (tcp->set_active (true)) {
+ delete tcp;
+ return 0;
+ }
+
+ return tcp;
+
+}
+
+void
+delete_tranzport_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+bool
+probe_tranzport_protocol (ControlProtocolDescriptor* descriptor)
+{
+ return TranzportControlProtocol::probe();
+}
+
+static ControlProtocolDescriptor tranzport_descriptor = {
+ name : "Tranzport",
+ id : "uri://ardour.org/surfaces/tranzport:0",
+ ptr : 0,
+ module : 0,
+ mandatory : 0,
+ supports_feedback : false,
+ probe : probe_tranzport_protocol,
+ initialize : new_tranzport_protocol,
+ destroy : delete_tranzport_protocol
+};
+
+
+extern "C" {
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &tranzport_descriptor;
+}
+}
+
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
index bbb78d31d1..c874a05de5 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
/* Design notes: The tranzport is a unique device, basically a
@@ -1562,7 +1561,7 @@ TranzportControlProtocol::button_event_record_release (bool shifted)
void button_event_mute (bool pressed, bool shifted)
{
- //static int was_pressed = 0;
+ static int was_pressed = 0;
// if(pressed) { }
}
diff --git a/libs/surfaces/frontier/tranzport/tranzport_control_protocol.h b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.h
new file mode 100644
index 0000000000..f13e4a3a44
--- /dev/null
+++ b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.h
@@ -0,0 +1,320 @@
+
+#ifndef ardour_tranzport_control_protocol_h
+#define ardour_tranzport_control_protocol_h
+
+#include <vector>
+
+#include <sys/time.h>
+#include <pthread.h>
+#include <usb.h>
+
+#include <glibmm/thread.h>
+
+#include <ardour/types.h>
+
+#include <control_protocol/control_protocol.h>
+
+class TranzportControlProtocol : public ARDOUR::ControlProtocol
+{
+ public:
+ TranzportControlProtocol (ARDOUR::Session&);
+ virtual ~TranzportControlProtocol();
+
+ int set_active (bool yn);
+
+ static bool probe ();
+
+ XMLNode& get_state ();
+ int set_state (const XMLNode&);
+
+ private:
+ static const int VENDORID = 0x165b;
+ static const int PRODUCTID = 0x8101;
+ static const int READ_ENDPOINT = 0x81;
+ static const int WRITE_ENDPOINT = 0x02;
+ const static int STATUS_OFFLINE = 0xff;
+ const static int STATUS_ONLINE = 0x01;
+ const static uint8_t WheelDirectionThreshold = 0x3f;
+
+ enum LightID {
+ LightRecord = 0,
+ LightTrackrec,
+ LightTrackmute,
+ LightTracksolo,
+ LightAnysolo,
+ LightLoop,
+ LightPunch
+ };
+
+ enum ButtonID {
+ ButtonBattery = 0x00004000,
+ ButtonBacklight = 0x00008000,
+ ButtonTrackLeft = 0x04000000,
+ ButtonTrackRight = 0x40000000,
+ ButtonTrackRec = 0x00040000,
+ ButtonTrackMute = 0x00400000,
+ ButtonTrackSolo = 0x00000400,
+ ButtonUndo = 0x80000000,
+ ButtonIn = 0x02000000,
+ ButtonOut = 0x20000000,
+ ButtonPunch = 0x00800000,
+ ButtonLoop = 0x00080000,
+ ButtonPrev = 0x00020000,
+ ButtonAdd = 0x00200000,
+ ButtonNext = 0x00000200,
+ ButtonRewind = 0x01000000,
+ ButtonFastForward = 0x10000000,
+ ButtonStop = 0x00010000,
+ ButtonPlay = 0x00100000,
+ ButtonRecord = 0x00000100,
+ ButtonShift = 0x08000000
+ };
+
+ enum WheelShiftMode {
+ WheelShiftGain,
+ WheelShiftPan,
+ WheelShiftMaster,
+ WheelShiftMarker
+ };
+
+ enum WheelMode {
+ WheelTimeline,
+ WheelScrub,
+ WheelShuttle
+ };
+
+ // FIXME - look at gtk2_ardour for snap settings
+
+ enum WheelIncrement {
+ WheelIncrSlave,
+ WheelIncrScreen,
+ WheelIncrSample,
+ WheelIncrBeat,
+ WheelIncrBar,
+ WheelIncrSecond,
+ WheelIncrMinute
+ };
+
+ enum DisplayMode {
+ DisplayNormal,
+ DisplayRecording,
+ DisplayRecordingMeter,
+ DisplayBigMeter,
+ DisplayConfig,
+ DisplayBling,
+ DisplayBlingMeter
+ };
+
+ enum BlingMode {
+ BlingOff,
+ BlingKit,
+ BlingRotating,
+ BlingPairs,
+ BlingRows,
+ BlingFlashAll
+ };
+
+ pthread_t thread;
+ uint32_t buttonmask;
+ uint32_t timeout;
+ uint32_t inflight;
+ uint8_t _datawheel;
+ uint8_t _device_status;
+ uint32_t current_track_id;
+ WheelMode wheel_mode;
+ WheelShiftMode wheel_shift_mode;
+ DisplayMode display_mode;
+ BlingMode bling_mode;
+ WheelIncrement wheel_increment;
+ usb_dev_handle* udev;
+
+ ARDOUR::gain_t gain_fraction;
+
+ Glib::Mutex update_lock;
+
+ bool screen_invalid[2][20];
+ char screen_current[2][20];
+ char screen_pending[2][20];
+ char screen_flash[2][20];
+
+ bool lights_invalid[7];
+ bool lights_current[7];
+ bool lights_pending[7];
+ bool lights_flash[7];
+
+ uint32_t last_bars;
+ uint32_t last_beats;
+ uint32_t last_ticks;
+
+ bool last_negative;
+ uint32_t last_hrs;
+ uint32_t last_mins;
+ uint32_t last_secs;
+ uint32_t last_frames;
+ nframes_t last_where;
+ ARDOUR::gain_t last_track_gain;
+ uint32_t last_meter_fill;
+ struct timeval last_wheel_motion;
+ int last_wheel_dir;
+
+ Glib::Mutex io_lock;
+
+ int open ();
+ int read (uint8_t *buf,uint32_t timeout_override = 0);
+ int write (uint8_t* cmd, uint32_t timeout_override = 0);
+ int write_noretry (uint8_t* cmd, uint32_t timeout_override = 0);
+ int close ();
+ int save(char *name = "default");
+ int load(char *name = "default");
+ void print (int row, int col, const char* text);
+ void print_noretry (int row, int col, const char* text);
+
+ int rtpriority_set(int priority = 52);
+ int rtpriority_unset(int priority = 0);
+
+ int open_core (struct usb_device*);
+
+ static void* _monitor_work (void* arg);
+ void* monitor_work ();
+
+ int process (uint8_t *);
+ int update_state();
+ void invalidate();
+ int flush();
+ // bool isuptodate(); // think on this. It seems futile to update more than 30/sec
+
+ // A screen is a cache of what should be on the lcd
+
+ void screen_init();
+ void screen_validate();
+ void screen_invalidate();
+ int screen_flush();
+ void screen_clear();
+ // bool screen_isuptodate(); // think on this -
+
+ // Commands to write to the lcd
+
+ int lcd_init();
+ bool lcd_damage();
+ bool lcd_isdamaged();
+
+ bool lcd_damage(int row, int col = 0, int length = 20);
+ bool lcd_isdamaged(int row, int col = 0, int length = 20);
+
+ int lcd_flush();
+ int lcd_write(uint8_t* cmd, uint32_t timeout_override = 0); // pedantic alias for write
+ void lcd_fill (uint8_t fill_char);
+ void lcd_clear ();
+ void lcd_print (int row, int col, const char* text);
+ void lcd_print_noretry (int row, int col, const char* text);
+
+ // Commands to write to the lights
+ // FIXME - on some devices lights can have intensity and colors
+
+ void lights_init();
+ void lights_validate();
+ void lights_invalidate();
+ void light_validate(LightID light);
+ void light_invalidate(LightID light);
+ int lights_flush();
+ int lights_write(uint8_t* cmd,uint32_t timeout_override = 0); // pedantic alias to write
+
+ // a cache of what should be lit
+
+ void lights_off ();
+ void lights_on ();
+ int light_set(LightID, bool offon = true);
+ int light_on (LightID);
+ int light_off (LightID);
+
+ // some modes for the lights, should probably be renamed
+
+ int lights_show_normal();
+ int lights_show_recording();
+ int lights_show_tempo();
+ int lights_show_bling();
+
+ void enter_big_meter_mode ();
+ void enter_normal_display_mode ();
+ void enter_config_mode();
+ void enter_recording_mode();
+ void enter_bling_mode();
+
+ void next_display_mode ();
+ void normal_update ();
+
+ void show_current_track ();
+ void show_track_gain ();
+ void show_transport_time ();
+ void show_bbt (nframes_t where);
+ void show_smpte (nframes_t where);
+ void show_wheel_mode ();
+ void show_gain ();
+ void show_pan ();
+ void show_meter ();
+
+ void datawheel ();
+ void scrub ();
+ void scroll ();
+ void shuttle ();
+ void config ();
+
+ void next_wheel_mode ();
+ void next_wheel_shift_mode ();
+
+ void set_current_track (ARDOUR::Route*);
+ void next_track ();
+ void prev_track ();
+ void step_gain_up ();
+ void step_gain_down ();
+ void step_pan_right ();
+ void step_pan_left ();
+
+
+ void button_event_battery_press (bool shifted);
+ void button_event_battery_release (bool shifted);
+ void button_event_backlight_press (bool shifted);
+ void button_event_backlight_release (bool shifted);
+ void button_event_trackleft_press (bool shifted);
+ void button_event_trackleft_release (bool shifted);
+ void button_event_trackright_press (bool shifted);
+ void button_event_trackright_release (bool shifted);
+ void button_event_trackrec_press (bool shifted);
+ void button_event_trackrec_release (bool shifted);
+ void button_event_trackmute_press (bool shifted);
+ void button_event_trackmute_release (bool shifted);
+ void button_event_tracksolo_press (bool shifted);
+ void button_event_tracksolo_release (bool shifted);
+ void button_event_undo_press (bool shifted);
+ void button_event_undo_release (bool shifted);
+ void button_event_in_press (bool shifted);
+ void button_event_in_release (bool shifted);
+ void button_event_out_press (bool shifted);
+ void button_event_out_release (bool shifted);
+ void button_event_punch_press (bool shifted);
+ void button_event_punch_release (bool shifted);
+ void button_event_loop_press (bool shifted);
+ void button_event_loop_release (bool shifted);
+ void button_event_prev_press (bool shifted);
+ void button_event_prev_release (bool shifted);
+ void button_event_add_press (bool shifted);
+ void button_event_add_release (bool shifted);
+ void button_event_next_press (bool shifted);
+ void button_event_next_release (bool shifted);
+ void button_event_rewind_press (bool shifted);
+ void button_event_rewind_release (bool shifted);
+ void button_event_fastforward_press (bool shifted);
+ void button_event_fastforward_release (bool shifted);
+ void button_event_stop_press (bool shifted);
+ void button_event_stop_release (bool shifted);
+ void button_event_play_press (bool shifted);
+ void button_event_play_release (bool shifted);
+ void button_event_record_press (bool shifted);
+ void button_event_record_release (bool shifted);
+
+ // new api
+ void button_event_mute (bool pressed, bool shifted);
+};
+
+
+#endif // ardour_tranzport_control_protocol_h
diff --git a/libs/surfaces/generic_midi/SConscript b/libs/surfaces/generic_midi/SConscript
index 6c76e05464..b092188852 100644
--- a/libs/surfaces/generic_midi/SConscript
+++ b/libs/surfaces/generic_midi/SConscript
@@ -40,8 +40,8 @@ genericmidi.Merge ([
libraries['sigc2'],
libraries['usb'],
libraries['xml'],
- libraries['glib2'],
- libraries['glibmm2']
+ libraries['glib2'],
+ libraries['glibmm2']
])
libardour_genericmidi = genericmidi.SharedLibrary('ardour_genericmidi', genericmidi_files)
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index 0256d5c359..1a9570c6a2 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#define __STDC_FORMAT_MACROS 1
@@ -130,7 +129,18 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
return false;
}
- MIDIControllable* mc = new MIDIControllable (*_port, *c);
+ MIDIControllable* mc = 0;
+
+ for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
+ if ((*i)->get_controllable().id() == c->id()) {
+ mc = *i;
+ break;
+ }
+ }
+
+ if (!mc) {
+ mc = new MIDIControllable (*_port, *c);
+ }
{
Glib::Mutex::Lock lm (pending_lock);
@@ -164,6 +174,8 @@ void
GenericMidiControlProtocol::stop_learning (Controllable* c)
{
Glib::Mutex::Lock lm (pending_lock);
+ Glib::Mutex::Lock lm2 (controllables_lock);
+ MIDIControllable* dptr = 0;
/* 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.
@@ -172,11 +184,22 @@ GenericMidiControlProtocol::stop_learning (Controllable* c)
for (MIDIControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) {
if (&(*i)->get_controllable() == c) {
(*i)->stop_learning ();
- delete (*i);
+ dptr = *i;
pending_controllables.erase (i);
break;
}
}
+
+ for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
+ if (&(*i)->get_controllable() == c) {
+ controllables.erase (i);
+ break;
+ }
+ }
+
+ if (dptr) {
+ delete dptr;
+ }
}
XMLNode&
@@ -248,7 +271,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node)
ID id = prop->value ();
- c = session->controllable_by_id (id);
+ c = Controllable::by_id (id);
if (c) {
MIDIControllable* mc = new MIDIControllable (*_port, *c);
@@ -257,8 +280,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node)
}
} else {
- warning << string_compose (_("Generic MIDI control: controllable %1 not found in session (ignored)"),
- id)
+ warning << string_compose (_("Generic MIDI control: controllable %1 not found (ignored)"), id)
<< endmsg;
}
}
diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc
index 75b5699f18..7f6f889df5 100644
--- a/libs/surfaces/generic_midi/midicontrollable.cc
+++ b/libs/surfaces/generic_midi/midicontrollable.cc
@@ -15,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: midicontrollable.cc 629 2006-06-21 23:01:03Z paul $
*/
#include <cstdio> /* for sprintf, sigh */
@@ -99,6 +98,8 @@ MIDIControllable::stop_learning ()
void
MIDIControllable::drop_external_control ()
{
+ cerr << "Dropping existing control using " << connections << " connections\n";
+
if (connections > 0) {
midi_sense_connection[0].disconnect ();
}
@@ -279,6 +280,8 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
default:
break;
}
+
+ cerr << "MIDI bound with " << connections << endl;
}
void
diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h
index 8b63172916..7e0243971c 100644
--- a/libs/surfaces/generic_midi/midicontrollable.h
+++ b/libs/surfaces/generic_midi/midicontrollable.h
@@ -15,7 +15,6 @@
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__
diff --git a/libs/surfaces/mackie/SConscript b/libs/surfaces/mackie/SConscript
new file mode 100644
index 0000000000..7bd1357cb3
--- /dev/null
+++ b/libs/surfaces/mackie/SConscript
@@ -0,0 +1,74 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+mackie = env.Copy()
+
+#
+# this defines the version number of libardour_mackie
+#
+
+domain = 'ardour_mackie'
+
+mackie.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+mackie.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+mackie.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+mackie.Append(PACKAGE = domain)
+mackie.Append(POTFILE = domain + '.pot')
+
+mackie_files=Split("""
+interface.cc
+midi_byte_array.cc
+controls.cc
+route_signal.cc
+mackie_midi_builder.cc
+mackie_button_handler.cc
+mackie_control_protocol_poll.cc
+surface_port.cc
+mackie_port.cc
+types.cc
+surface.cc
+mackie_control_protocol.cc
+bcf_surface.cc
+mackie_surface.cc
+""")
+
+mackie.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+mackie.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+mackie.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+mackie.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+mackie.Merge ([
+ libraries['ardour'],
+ libraries['ardour_cp'],
+ libraries['sigc2'],
+ libraries['pbd'],
+ libraries['midi++2'],
+ libraries['xml'],
+ libraries['glib2'],
+ libraries['glibmm2'],
+ libraries['sndfile-ardour']
+ ])
+
+libardour_mackie = mackie.SharedLibrary('ardour_mackie', mackie_files)
+
+test_files = Split("""
+midi_byte_array.cc
+test.cc
+""")
+mackie_test = Program('mackie_test', test_files )
+
+if mackie['SURFACES']:
+ Default(libardour_mackie)
+ if env['NLS']:
+ i18n (mackie, mackie_files, env)
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2','surfaces'), libardour_mackie))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript' ] +
+ mackie_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/mackie/TODO b/libs/surfaces/mackie/TODO
new file mode 100644
index 0000000000..a9cb1b9878
--- /dev/null
+++ b/libs/surfaces/mackie/TODO
@@ -0,0 +1,45 @@
+* how long can UI signal callbacks take to execute? What happens if they block?
+ where ENSURE_CORRECT_THREAD is a macro that is modelled on ENSURE_GUI_THREAD
+ if the handler is not called in the "correct thread", it will use a pseudo-RT-safe-enough technique to get the correct thread to recall "handler" later on, and return.
+
+* jog with transport rolling doesn't work properly. My use of ScrollTimeline also doesn't work.
+* make loop button sensitive to current transport state
+* make sure rew button can go past the previous if pressed twice, relatively quickly.
+* finish button mapping. Only shifted buttons left for bcf.
+* concurrency for bank switching? And make sure "old" events aren't sent to "new" faders
+* TODOs in code
+* removal of a route results in a strip that isn't dead, but doesn't have any effect on the session
+* use i18n. see string_compose
+* docs in manual, including button assignment diagram
+
+Later
+-----
+* remove commented couts
+* Queueing of writes?
+* Generic surface code to common location
+* bulk remote id changes cause too many surface updates. use Config->remote_model.
+* which bank switching - overlap or dead faders? Option?
+* signals for buttons?
+* MackieControlProtocol in namespace Mackie?
+* power-cycling of surface. fd_midiport doesn't close.
+* mix busses and/or a "bus-only" bank/mode
+* what about surfaces like Mackie C4 and BCR2000?
+
+Need UI integration
+-------------------
+* Some indication on the UI of currently bank-switched-in routes?
+ Useful for surfaces that don't have a scribble strip.
+* use current zoom setting and snap state for shuttle wheel
+
+Actual Mackie
+-------------
+* docs claim that unit will send a host query on init.
+* test Mackie surface object. Apparently led rings don't work. Stereo busses?
+* timecode & 55 char displays
+* midi bandwidth
+
+Bugs
+----
+
+* definitely something wrong with remote_id assignment on session create
+ (master strip assigned 0).
diff --git a/libs/surfaces/mackie/bcf_surface.cc b/libs/surfaces/mackie/bcf_surface.cc
new file mode 100644
index 0000000000..2aaa70fc3e
--- /dev/null
+++ b/libs/surfaces/mackie/bcf_surface.cc
@@ -0,0 +1,1473 @@
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "bcf_surface.h"
+
+#include "controls.h"
+#include "mackie_button_handler.h"
+
+using namespace Mackie;
+
+void Mackie::BcfSurface::init_controls()
+{
+ // intialise groups and strips
+ Group * group = 0;
+
+ // make sure there are enough strips
+ strips.resize( 7 );
+
+ group = new Group ( "user" );
+ groups["user"] = group;
+
+ group = new Group ( "assignment" );
+ groups["assignment"] = group;
+
+ group = new Group ( "none" );
+ groups["none"] = group;
+
+ group = new MasterStrip ( "master", 0 );
+ groups["master"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_1", 0 );
+ groups["strip_1"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "cursor" );
+ groups["cursor"] = group;
+
+ group = new Strip ( "strip_2", 1 );
+ groups["strip_2"] = group;
+ strips[1] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "functions" );
+ groups["functions"] = group;
+
+ group = new Group ( "automation" );
+ groups["automation"] = group;
+
+ group = new Strip ( "strip_3", 2 );
+ groups["strip_3"] = group;
+ strips[2] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "display" );
+ groups["display"] = group;
+
+ group = new Strip ( "strip_4", 3 );
+ groups["strip_4"] = group;
+ strips[3] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_5", 4 );
+ groups["strip_5"] = group;
+ strips[4] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_6", 5 );
+ groups["strip_6"] = group;
+ strips[5] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "transport" );
+ groups["transport"] = group;
+
+ group = new Strip ( "strip_7", 6 );
+ groups["strip_7"] = group;
+ strips[6] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "modifiers" );
+ groups["modifiers"] = group;
+
+ group = new Group ( "bank" );
+ groups["bank"] = group;
+
+
+ // initialise controls
+ Control * control = 0;
+
+ group = groups["strip_1"];
+ control = new Fader ( 0, 1, "gain", *group );
+ faders[0x00] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Fader ( 1, 2, "gain", *group );
+ faders[0x01] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Fader ( 2, 3, "gain", *group );
+ faders[0x02] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Fader ( 3, 4, "gain", *group );
+ faders[0x03] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Fader ( 4, 5, "gain", *group );
+ faders[0x04] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Fader ( 5, 6, "gain", *group );
+ faders[0x05] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Fader ( 6, 7, "gain", *group );
+ faders[0x06] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["master"];
+ control = new Fader ( 7, 1, "gain", *group );
+ faders[0x07] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Pot ( 16, 1, "vpot", *group );
+ pots[0x10] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Pot ( 17, 2, "vpot", *group );
+ pots[0x11] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Pot ( 18, 3, "vpot", *group );
+ pots[0x12] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Pot ( 19, 4, "vpot", *group );
+ pots[0x13] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Pot ( 20, 5, "vpot", *group );
+ pots[0x14] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Pot ( 21, 6, "vpot", *group );
+ pots[0x15] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Pot ( 22, 7, "vpot", *group );
+ pots[0x16] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Pot ( 23, 1, "jog", *group );
+ pots[0x17] = control;
+ controls.push_back( control );
+ controls_by_name["jog"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Pot ( 46, 1, "external", *group );
+ pots[0x2e] = control;
+ controls.push_back( control );
+ controls_by_name["external"] = control;
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 24, 1, "recenable", *group );
+ buttons[0x18] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 25, 2, "recenable", *group );
+ buttons[0x19] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 26, 3, "recenable", *group );
+ buttons[0x1a] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 27, 4, "recenable", *group );
+ buttons[0x1b] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 28, 5, "recenable", *group );
+ buttons[0x1c] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 29, 6, "recenable", *group );
+ buttons[0x1d] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 30, 7, "recenable", *group );
+ buttons[0x1e] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 32, 1, "solo", *group );
+ buttons[0x20] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 33, 2, "solo", *group );
+ buttons[0x21] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 34, 3, "solo", *group );
+ buttons[0x22] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 35, 4, "solo", *group );
+ buttons[0x23] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 36, 5, "solo", *group );
+ buttons[0x24] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 37, 6, "solo", *group );
+ buttons[0x25] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 38, 7, "solo", *group );
+ buttons[0x26] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 16, 1, "mute", *group );
+ buttons[0x10] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 17, 2, "mute", *group );
+ buttons[0x11] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 18, 3, "mute", *group );
+ buttons[0x12] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 19, 4, "mute", *group );
+ buttons[0x13] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 20, 5, "mute", *group );
+ buttons[0x14] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 21, 6, "mute", *group );
+ buttons[0x15] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 22, 7, "mute", *group );
+ buttons[0x16] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 0, 1, "select", *group );
+ buttons[0x00] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 1, 2, "select", *group );
+ buttons[0x01] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 2, 3, "select", *group );
+ buttons[0x02] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 3, 4, "select", *group );
+ buttons[0x03] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 4, 5, "select", *group );
+ buttons[0x04] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 5, 6, "select", *group );
+ buttons[0x05] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 6, 7, "select", *group );
+ buttons[0x06] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 8, 1, "vselect", *group );
+ buttons[0x08] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 9, 2, "vselect", *group );
+ buttons[0x09] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 10, 3, "vselect", *group );
+ buttons[0x0a] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 11, 4, "vselect", *group );
+ buttons[0x0b] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 12, 5, "vselect", *group );
+ buttons[0x0c] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 13, 6, "vselect", *group );
+ buttons[0x0d] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 14, 7, "vselect", *group );
+ buttons[0x0e] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 40, 1, "io", *group );
+ buttons[0x28] = control;
+ controls.push_back( control );
+ controls_by_name["io"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 90, 1, "sends", *group );
+ buttons[0x5a] = control;
+ controls.push_back( control );
+ controls_by_name["sends"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 89, 1, "pan", *group );
+ buttons[0x59] = control;
+ controls.push_back( control );
+ controls_by_name["pan"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 87, 1, "plugin", *group );
+ buttons[0x57] = control;
+ controls.push_back( control );
+ controls_by_name["plugin"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 88, 1, "eq", *group );
+ buttons[0x58] = control;
+ controls.push_back( control );
+ controls_by_name["eq"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 45, 1, "dyn", *group );
+ buttons[0x2d] = control;
+ controls.push_back( control );
+ controls_by_name["dyn"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 46, 1, "left", *group );
+ buttons[0x2e] = control;
+ controls.push_back( control );
+ controls_by_name["left"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 47, 1, "right", *group );
+ buttons[0x2f] = control;
+ controls.push_back( control );
+ controls_by_name["right"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 48, 1, "channel_left", *group );
+ buttons[0x30] = control;
+ controls.push_back( control );
+ controls_by_name["channel_left"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 49, 1, "channel_right", *group );
+ buttons[0x31] = control;
+ controls.push_back( control );
+ controls_by_name["channel_right"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 50, 1, "flip", *group );
+ buttons[0x32] = control;
+ controls.push_back( control );
+ controls_by_name["flip"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 86, 1, "edit", *group );
+ buttons[0x56] = control;
+ controls.push_back( control );
+ controls_by_name["edit"] = control;
+ group->add( *control );
+
+ group = groups["display"];
+ control = new Button ( 52, 1, "name_value", *group );
+ buttons[0x34] = control;
+ controls.push_back( control );
+ controls_by_name["name_value"] = control;
+ group->add( *control );
+
+ group = groups["display"];
+ control = new Button ( 53, 1, "smpte_beats", *group );
+ buttons[0x35] = control;
+ controls.push_back( control );
+ controls_by_name["smpte_beats"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 54, 1, "F1", *group );
+ buttons[0x36] = control;
+ controls.push_back( control );
+ controls_by_name["F1"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 55, 1, "F2", *group );
+ buttons[0x37] = control;
+ controls.push_back( control );
+ controls_by_name["F2"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 56, 1, "F3", *group );
+ buttons[0x38] = control;
+ controls.push_back( control );
+ controls_by_name["F3"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 57, 1, "F4", *group );
+ buttons[0x39] = control;
+ controls.push_back( control );
+ controls_by_name["F4"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 58, 1, "F5", *group );
+ buttons[0x3a] = control;
+ controls.push_back( control );
+ controls_by_name["F5"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 59, 1, "F6", *group );
+ buttons[0x3b] = control;
+ controls.push_back( control );
+ controls_by_name["F6"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 60, 1, "F7", *group );
+ buttons[0x3c] = control;
+ controls.push_back( control );
+ controls_by_name["F7"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 61, 1, "F8", *group );
+ buttons[0x3d] = control;
+ controls.push_back( control );
+ controls_by_name["F8"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 62, 1, "F9", *group );
+ buttons[0x3e] = control;
+ controls.push_back( control );
+ controls_by_name["F9"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 63, 1, "F10", *group );
+ buttons[0x3f] = control;
+ controls.push_back( control );
+ controls_by_name["F10"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 64, 1, "F11", *group );
+ buttons[0x40] = control;
+ controls.push_back( control );
+ controls_by_name["F11"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 65, 1, "F12", *group );
+ buttons[0x41] = control;
+ controls.push_back( control );
+ controls_by_name["F12"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 66, 1, "F13", *group );
+ buttons[0x42] = control;
+ controls.push_back( control );
+ controls_by_name["F13"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 67, 1, "F14", *group );
+ buttons[0x43] = control;
+ controls.push_back( control );
+ controls_by_name["F14"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 68, 1, "F15", *group );
+ buttons[0x44] = control;
+ controls.push_back( control );
+ controls_by_name["F15"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 69, 1, "F16", *group );
+ buttons[0x45] = control;
+ controls.push_back( control );
+ controls_by_name["F16"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 39, 1, "global_solo", *group );
+ buttons[0x27] = control;
+ controls.push_back( control );
+ controls_by_name["global_solo"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 71, 1, "option", *group );
+ buttons[0x47] = control;
+ controls.push_back( control );
+ controls_by_name["option"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 72, 1, "control", *group );
+ buttons[0x48] = control;
+ controls.push_back( control );
+ controls_by_name["control"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 73, 1, "cmd_alt", *group );
+ buttons[0x49] = control;
+ controls.push_back( control );
+ controls_by_name["cmd_alt"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 74, 1, "on", *group );
+ buttons[0x4a] = control;
+ controls.push_back( control );
+ controls_by_name["on"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 75, 1, "rec_ready", *group );
+ buttons[0x4b] = control;
+ controls.push_back( control );
+ controls_by_name["rec_ready"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 76, 1, "undo", *group );
+ buttons[0x4c] = control;
+ controls.push_back( control );
+ controls_by_name["undo"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 77, 1, "snapshot", *group );
+ buttons[0x4d] = control;
+ controls.push_back( control );
+ controls_by_name["snapshot"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 78, 1, "touch", *group );
+ buttons[0x4e] = control;
+ controls.push_back( control );
+ controls_by_name["touch"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 79, 1, "redo", *group );
+ buttons[0x4f] = control;
+ controls.push_back( control );
+ controls_by_name["redo"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 80, 1, "marker", *group );
+ buttons[0x50] = control;
+ controls.push_back( control );
+ controls_by_name["marker"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 81, 1, "enter", *group );
+ buttons[0x51] = control;
+ controls.push_back( control );
+ controls_by_name["enter"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 82, 1, "cancel", *group );
+ buttons[0x52] = control;
+ controls.push_back( control );
+ controls_by_name["cancel"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 83, 1, "mixer", *group );
+ buttons[0x53] = control;
+ controls.push_back( control );
+ controls_by_name["mixer"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 84, 1, "frm_left", *group );
+ buttons[0x54] = control;
+ controls.push_back( control );
+ controls_by_name["frm_left"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 85, 1, "frm_right", *group );
+ buttons[0x55] = control;
+ controls.push_back( control );
+ controls_by_name["frm_right"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 70, 1, "loop", *group );
+ buttons[0x46] = control;
+ controls.push_back( control );
+ controls_by_name["loop"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 44, 1, "punch_in", *group );
+ buttons[0x2c] = control;
+ controls.push_back( control );
+ controls_by_name["punch_in"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 43, 1, "punch_out", *group );
+ buttons[0x2b] = control;
+ controls.push_back( control );
+ controls_by_name["punch_out"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 42, 1, "home", *group );
+ buttons[0x2a] = control;
+ controls.push_back( control );
+ controls_by_name["home"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 41, 1, "end", *group );
+ buttons[0x29] = control;
+ controls.push_back( control );
+ controls_by_name["end"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 91, 1, "rewind", *group );
+ buttons[0x5b] = control;
+ controls.push_back( control );
+ controls_by_name["rewind"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 92, 1, "ffwd", *group );
+ buttons[0x5c] = control;
+ controls.push_back( control );
+ controls_by_name["ffwd"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 93, 1, "stop", *group );
+ buttons[0x5d] = control;
+ controls.push_back( control );
+ controls_by_name["stop"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 94, 1, "play", *group );
+ buttons[0x5e] = control;
+ controls.push_back( control );
+ controls_by_name["play"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 31, 1, "record", *group );
+ buttons[0x1f] = control;
+ controls.push_back( control );
+ controls_by_name["record"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 96, 1, "cursor_up", *group );
+ buttons[0x60] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_up"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 97, 1, "cursor_down", *group );
+ buttons[0x61] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_down"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 98, 1, "cursor_left", *group );
+ buttons[0x62] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_left"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 99, 1, "cursor_right", *group );
+ buttons[0x63] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_right"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 100, 1, "zoom", *group );
+ buttons[0x64] = control;
+ controls.push_back( control );
+ controls_by_name["zoom"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 101, 1, "scrub", *group );
+ buttons[0x65] = control;
+ controls.push_back( control );
+ controls_by_name["scrub"] = control;
+ group->add( *control );
+
+ group = groups["user"];
+ control = new Button ( 102, 1, "user_a", *group );
+ buttons[0x66] = control;
+ controls.push_back( control );
+ controls_by_name["user_a"] = control;
+ group->add( *control );
+
+ group = groups["user"];
+ control = new Button ( 103, 1, "user_b", *group );
+ buttons[0x67] = control;
+ controls.push_back( control );
+ controls_by_name["user_b"] = control;
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 104, 1, "fader_touch", *group );
+ buttons[0x68] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 105, 2, "fader_touch", *group );
+ buttons[0x69] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 106, 3, "fader_touch", *group );
+ buttons[0x6a] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 107, 4, "fader_touch", *group );
+ buttons[0x6b] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 108, 5, "fader_touch", *group );
+ buttons[0x6c] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 109, 6, "fader_touch", *group );
+ buttons[0x6d] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 110, 7, "fader_touch", *group );
+ buttons[0x6e] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["master"];
+ control = new Button ( 111, 1, "fader_touch", *group );
+ buttons[0x6f] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["master"];
+ control = new Button ( 23, 1, "mute", *group );
+ buttons[0x17] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 51, 1, "clicking", *group );
+ buttons[0x33] = control;
+ controls.push_back( control );
+ controls_by_name["clicking"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 113, 1, "smpte", *group );
+ leds[0x71] = control;
+ controls.push_back( control );
+ controls_by_name["smpte"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 114, 1, "beats", *group );
+ leds[0x72] = control;
+ controls.push_back( control );
+ controls_by_name["beats"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 115, 1, "solo", *group );
+ leds[0x73] = control;
+ controls.push_back( control );
+ controls_by_name["solo"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 118, 1, "relay_click", *group );
+ leds[0x76] = control;
+ controls.push_back( control );
+ controls_by_name["relay_click"] = control;
+ group->add( *control );
+
+}
+
+void Mackie::BcfSurface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
+{
+ if ( bs != press && bs != release )
+ {
+ mbh.update_led( button, none );
+ return;
+ }
+
+ LedState ls;
+ switch ( button.id() )
+ {
+
+ case 0x28: // io
+ switch ( bs ) {
+ case press: ls = mbh.io_press( button ); break;
+ case release: ls = mbh.io_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5a: // sends
+ switch ( bs ) {
+ case press: ls = mbh.sends_press( button ); break;
+ case release: ls = mbh.sends_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x59: // pan
+ switch ( bs ) {
+ case press: ls = mbh.pan_press( button ); break;
+ case release: ls = mbh.pan_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x57: // plugin
+ switch ( bs ) {
+ case press: ls = mbh.plugin_press( button ); break;
+ case release: ls = mbh.plugin_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x58: // eq
+ switch ( bs ) {
+ case press: ls = mbh.eq_press( button ); break;
+ case release: ls = mbh.eq_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2d: // dyn
+ switch ( bs ) {
+ case press: ls = mbh.dyn_press( button ); break;
+ case release: ls = mbh.dyn_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2e: // left
+ switch ( bs ) {
+ case press: ls = mbh.left_press( button ); break;
+ case release: ls = mbh.left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2f: // right
+ switch ( bs ) {
+ case press: ls = mbh.right_press( button ); break;
+ case release: ls = mbh.right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x30: // channel_left
+ switch ( bs ) {
+ case press: ls = mbh.channel_left_press( button ); break;
+ case release: ls = mbh.channel_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x31: // channel_right
+ switch ( bs ) {
+ case press: ls = mbh.channel_right_press( button ); break;
+ case release: ls = mbh.channel_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x32: // flip
+ switch ( bs ) {
+ case press: ls = mbh.flip_press( button ); break;
+ case release: ls = mbh.flip_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x56: // edit
+ switch ( bs ) {
+ case press: ls = mbh.edit_press( button ); break;
+ case release: ls = mbh.edit_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x34: // name_value
+ switch ( bs ) {
+ case press: ls = mbh.name_value_press( button ); break;
+ case release: ls = mbh.name_value_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x35: // smpte_beats
+ switch ( bs ) {
+ case press: ls = mbh.smpte_beats_press( button ); break;
+ case release: ls = mbh.smpte_beats_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x36: // F1
+ switch ( bs ) {
+ case press: ls = mbh.F1_press( button ); break;
+ case release: ls = mbh.F1_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x37: // F2
+ switch ( bs ) {
+ case press: ls = mbh.F2_press( button ); break;
+ case release: ls = mbh.F2_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x38: // F3
+ switch ( bs ) {
+ case press: ls = mbh.F3_press( button ); break;
+ case release: ls = mbh.F3_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x39: // F4
+ switch ( bs ) {
+ case press: ls = mbh.F4_press( button ); break;
+ case release: ls = mbh.F4_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3a: // F5
+ switch ( bs ) {
+ case press: ls = mbh.F5_press( button ); break;
+ case release: ls = mbh.F5_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3b: // F6
+ switch ( bs ) {
+ case press: ls = mbh.F6_press( button ); break;
+ case release: ls = mbh.F6_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3c: // F7
+ switch ( bs ) {
+ case press: ls = mbh.F7_press( button ); break;
+ case release: ls = mbh.F7_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3d: // F8
+ switch ( bs ) {
+ case press: ls = mbh.F8_press( button ); break;
+ case release: ls = mbh.F8_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3e: // F9
+ switch ( bs ) {
+ case press: ls = mbh.F9_press( button ); break;
+ case release: ls = mbh.F9_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3f: // F10
+ switch ( bs ) {
+ case press: ls = mbh.F10_press( button ); break;
+ case release: ls = mbh.F10_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x40: // F11
+ switch ( bs ) {
+ case press: ls = mbh.F11_press( button ); break;
+ case release: ls = mbh.F11_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x41: // F12
+ switch ( bs ) {
+ case press: ls = mbh.F12_press( button ); break;
+ case release: ls = mbh.F12_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x42: // F13
+ switch ( bs ) {
+ case press: ls = mbh.F13_press( button ); break;
+ case release: ls = mbh.F13_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x43: // F14
+ switch ( bs ) {
+ case press: ls = mbh.F14_press( button ); break;
+ case release: ls = mbh.F14_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x44: // F15
+ switch ( bs ) {
+ case press: ls = mbh.F15_press( button ); break;
+ case release: ls = mbh.F15_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x45: // F16
+ switch ( bs ) {
+ case press: ls = mbh.F16_press( button ); break;
+ case release: ls = mbh.F16_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x27: // global_solo
+ switch ( bs ) {
+ case press: ls = mbh.global_solo_press( button ); break;
+ case release: ls = mbh.global_solo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x47: // option
+ switch ( bs ) {
+ case press: ls = mbh.option_press( button ); break;
+ case release: ls = mbh.option_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x48: // control
+ switch ( bs ) {
+ case press: ls = mbh.control_press( button ); break;
+ case release: ls = mbh.control_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x49: // cmd_alt
+ switch ( bs ) {
+ case press: ls = mbh.cmd_alt_press( button ); break;
+ case release: ls = mbh.cmd_alt_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4a: // on
+ switch ( bs ) {
+ case press: ls = mbh.on_press( button ); break;
+ case release: ls = mbh.on_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4b: // rec_ready
+ switch ( bs ) {
+ case press: ls = mbh.rec_ready_press( button ); break;
+ case release: ls = mbh.rec_ready_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4c: // undo
+ switch ( bs ) {
+ case press: ls = mbh.undo_press( button ); break;
+ case release: ls = mbh.undo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4d: // snapshot
+ switch ( bs ) {
+ case press: ls = mbh.snapshot_press( button ); break;
+ case release: ls = mbh.snapshot_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4e: // touch
+ switch ( bs ) {
+ case press: ls = mbh.touch_press( button ); break;
+ case release: ls = mbh.touch_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4f: // redo
+ switch ( bs ) {
+ case press: ls = mbh.redo_press( button ); break;
+ case release: ls = mbh.redo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x50: // marker
+ switch ( bs ) {
+ case press: ls = mbh.marker_press( button ); break;
+ case release: ls = mbh.marker_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x51: // enter
+ switch ( bs ) {
+ case press: ls = mbh.enter_press( button ); break;
+ case release: ls = mbh.enter_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x52: // cancel
+ switch ( bs ) {
+ case press: ls = mbh.cancel_press( button ); break;
+ case release: ls = mbh.cancel_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x53: // mixer
+ switch ( bs ) {
+ case press: ls = mbh.mixer_press( button ); break;
+ case release: ls = mbh.mixer_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x54: // frm_left
+ switch ( bs ) {
+ case press: ls = mbh.frm_left_press( button ); break;
+ case release: ls = mbh.frm_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x55: // frm_right
+ switch ( bs ) {
+ case press: ls = mbh.frm_right_press( button ); break;
+ case release: ls = mbh.frm_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x46: // loop
+ switch ( bs ) {
+ case press: ls = mbh.loop_press( button ); break;
+ case release: ls = mbh.loop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2c: // punch_in
+ switch ( bs ) {
+ case press: ls = mbh.punch_in_press( button ); break;
+ case release: ls = mbh.punch_in_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2b: // punch_out
+ switch ( bs ) {
+ case press: ls = mbh.punch_out_press( button ); break;
+ case release: ls = mbh.punch_out_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2a: // home
+ switch ( bs ) {
+ case press: ls = mbh.home_press( button ); break;
+ case release: ls = mbh.home_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x29: // end
+ switch ( bs ) {
+ case press: ls = mbh.end_press( button ); break;
+ case release: ls = mbh.end_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5b: // rewind
+ switch ( bs ) {
+ case press: ls = mbh.rewind_press( button ); break;
+ case release: ls = mbh.rewind_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5c: // ffwd
+ switch ( bs ) {
+ case press: ls = mbh.ffwd_press( button ); break;
+ case release: ls = mbh.ffwd_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5d: // stop
+ switch ( bs ) {
+ case press: ls = mbh.stop_press( button ); break;
+ case release: ls = mbh.stop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5e: // play
+ switch ( bs ) {
+ case press: ls = mbh.play_press( button ); break;
+ case release: ls = mbh.play_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x1f: // record
+ switch ( bs ) {
+ case press: ls = mbh.record_press( button ); break;
+ case release: ls = mbh.record_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x60: // cursor_up
+ switch ( bs ) {
+ case press: ls = mbh.cursor_up_press( button ); break;
+ case release: ls = mbh.cursor_up_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x61: // cursor_down
+ switch ( bs ) {
+ case press: ls = mbh.cursor_down_press( button ); break;
+ case release: ls = mbh.cursor_down_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x62: // cursor_left
+ switch ( bs ) {
+ case press: ls = mbh.cursor_left_press( button ); break;
+ case release: ls = mbh.cursor_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x63: // cursor_right
+ switch ( bs ) {
+ case press: ls = mbh.cursor_right_press( button ); break;
+ case release: ls = mbh.cursor_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x64: // zoom
+ switch ( bs ) {
+ case press: ls = mbh.zoom_press( button ); break;
+ case release: ls = mbh.zoom_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x65: // scrub
+ switch ( bs ) {
+ case press: ls = mbh.scrub_press( button ); break;
+ case release: ls = mbh.scrub_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x66: // user_a
+ switch ( bs ) {
+ case press: ls = mbh.user_a_press( button ); break;
+ case release: ls = mbh.user_a_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x67: // user_b
+ switch ( bs ) {
+ case press: ls = mbh.user_b_press( button ); break;
+ case release: ls = mbh.user_b_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x33: // clicking
+ switch ( bs ) {
+ case press: ls = mbh.clicking_press( button ); break;
+ case release: ls = mbh.clicking_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ }
+ mbh.update_led( button, ls );
+}
diff --git a/libs/surfaces/mackie/bcf_surface.h b/libs/surfaces/mackie/bcf_surface.h
new file mode 100644
index 0000000000..a5fd3bf5a3
--- /dev/null
+++ b/libs/surfaces/mackie/bcf_surface.h
@@ -0,0 +1,27 @@
+#ifndef mackie_surface_bcf_h
+#define mackie_surface_bcf_h
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "surface.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler;
+
+class BcfSurface : public Surface
+{
+public:
+ BcfSurface( uint32_t max_strips ) : Surface( max_strips )
+ {
+ }
+
+ virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
+ virtual void init_controls();
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/controls.cc b/libs/surfaces/mackie/controls.cc
new file mode 100644
index 0000000000..e9808119b2
--- /dev/null
+++ b/libs/surfaces/mackie/controls.cc
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 "controls.h"
+#include "types.h"
+#include "mackie_midi_builder.h"
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+
+using namespace Mackie;
+using namespace std;
+
+void Group::add( Control & control )
+{
+ _controls.push_back( &control );
+}
+
+Strip::Strip( const std::string & name, int index )
+ : Group( name )
+ , _solo( 0 )
+ , _recenable( 0 )
+ , _mute( 0 )
+ , _select( 0 )
+ , _vselect( 0 )
+ , _fader_touch( 0 )
+ , _vpot( 0 )
+ , _gain( 0 )
+ , _index( index )
+{
+}
+
+/**
+ generated with
+
+controls[1].each do |x|
+ puts <<EOF
+#{x.class.name} & Strip::#{x.name}()
+{
+ if ( _#{x.name} == 0 )
+ throw MackieControlException( "#{x.name} is null" );
+ return *_#{x.name};
+}
+EOF
+end
+*/
+Fader & Strip::gain()
+{
+ if ( _gain == 0 )
+ throw MackieControlException( "gain is null" );
+ return *_gain;
+}
+Pot & Strip::vpot()
+{
+ if ( _vpot == 0 )
+ throw MackieControlException( "vpot is null" );
+ return *_vpot;
+}
+Button & Strip::recenable()
+{
+ if ( _recenable == 0 )
+ throw MackieControlException( "recenable is null" );
+ return *_recenable;
+}
+Button & Strip::solo()
+{
+ if ( _solo == 0 )
+ throw MackieControlException( "solo is null" );
+ return *_solo;
+}
+Button & Strip::mute()
+{
+ if ( _mute == 0 )
+ throw MackieControlException( "mute is null" );
+ return *_mute;
+}
+Button & Strip::select()
+{
+ if ( _select == 0 )
+ throw MackieControlException( "select is null" );
+ return *_select;
+}
+Button & Strip::vselect()
+{
+ if ( _vselect == 0 )
+ throw MackieControlException( "vselect is null" );
+ return *_vselect;
+}
+Button & Strip::fader_touch()
+{
+ if ( _fader_touch == 0 )
+ throw MackieControlException( "fader_touch is null" );
+ return *_fader_touch;
+}
diff --git a/libs/surfaces/mackie/controls.h b/libs/surfaces/mackie/controls.h
new file mode 100644
index 0000000000..1092c40453
--- /dev/null
+++ b/libs/surfaces/mackie/controls.h
@@ -0,0 +1,301 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 mackie_controls_h
+#define mackie_controls_h
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "mackie_control_exception.h"
+
+namespace Mackie
+{
+
+class Control;
+
+/**
+ This is a loose group of controls, eg cursor buttons,
+ transport buttons, functions buttons etc.
+*/
+class Group
+{
+public:
+ Group( const std::string & name )
+ : _name( name )
+ {
+ }
+
+ virtual ~Group() {}
+
+ virtual bool is_strip() const
+ {
+ return false;
+ }
+
+ virtual bool is_master() const
+ {
+ return false;
+ }
+
+ virtual void add( Control & control );
+
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ // This is for Surface only
+ void name( const std::string & rhs ) { _name = rhs; }
+
+ typedef std::vector<Control*> Controls;
+ const Controls & controls() const { return _controls; }
+
+protected:
+ Controls _controls;
+
+private:
+ std::string _name;
+};
+
+class Button;
+class Pot;
+class Fader;
+
+/**
+ This is the set of controls that make up a strip.
+*/
+class Strip : public Group
+{
+public:
+ Strip( const std::string & name, int index );
+
+ virtual bool is_strip() const
+ {
+ return true;
+ }
+
+ virtual void add( Control & control );
+
+ /// This is the index of the strip
+ int index() const { return _index; }
+
+ /// This is for Surface only
+ void index( int rhs ) { _index = rhs; }
+
+ Button & solo();
+ Button & recenable();
+ Button & mute();
+ Button & select();
+ Button & vselect();
+ Button & fader_touch();
+ Pot & vpot();
+ Fader & gain();
+
+ bool has_solo() { return _solo != 0; }
+ bool has_recenable() { return _recenable != 0; }
+ bool has_mute() { return _mute != 0; }
+ bool has_select() { return _select != 0; }
+ bool has_vselect() { return _vselect != 0; }
+ bool has_fader_touch() { return _fader_touch != 0; }
+ bool has_vpot() { return _vpot != 0; }
+ bool has_gain() { return _gain != 0; }
+
+private:
+ Button * _solo;
+ Button * _recenable;
+ Button * _mute;
+ Button * _select;
+ Button * _vselect;
+ Button * _fader_touch;
+ Pot * _vpot;
+ Fader * _gain;
+ int _index;
+};
+
+class MasterStrip : public Strip
+{
+public:
+ MasterStrip( const std::string & name, int index )
+ : Strip( name, index )
+ {
+ }
+
+ virtual bool is_master() const
+ {
+ return true;
+ }
+};
+
+class Led;
+
+/**
+ The base class for controls on the surface. They deliberately
+ don't know the midi protocol for updating them.
+*/
+class Control
+{
+public:
+ enum type_t { type_fader, type_button, type_pot, type_led, type_led_ring };
+
+ Control( int id, int ordinal, std::string name, Group & group )
+ : _id( id ), _ordinal( ordinal ), _name( name ), _group( group )
+ {
+ }
+
+ virtual ~Control() {}
+
+ virtual const Led & led() const
+ {
+ throw MackieControlException( "no led available" );
+ }
+
+ /// The midi id of the control
+ int id() const
+ {
+ return _id;
+ }
+
+ /// The 1-based number of the control
+ int ordinal() const
+ {
+ return _ordinal;
+ }
+
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ const Group & group() const
+ {
+ return _group;
+ }
+
+ const Strip & strip() const
+ {
+ return dynamic_cast<const Strip&>( _group );
+ }
+
+ Strip & strip()
+ {
+ return dynamic_cast<Strip&>( _group );
+ }
+
+ virtual bool accepts_feedback() const
+ {
+ return true;
+ }
+
+ virtual type_t type() const = 0;
+
+private:
+ int _id;
+ int _ordinal;
+ std::string _name;
+ Group & _group;
+};
+
+std::ostream & operator << ( std::ostream & os, const Control & control );
+
+class Fader : public Control
+{
+public:
+ Fader( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ , _touch( false )
+ {
+ }
+
+ bool touch() const { return _touch; }
+
+ void touch( bool yn ) { _touch = yn; }
+
+ virtual type_t type() const { return type_fader; }
+
+private:
+ bool _touch;
+};
+
+class Led : public Control
+{
+public:
+ Led( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ {
+ }
+
+ virtual const Led & led() const { return *this; }
+
+ virtual type_t type() const { return type_led; }
+};
+
+class Button : public Control
+{
+public:
+ Button( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ , _led( id, ordinal, name + "_led", group )
+ {
+ }
+
+ virtual const Led & led() const
+ {
+ return _led;
+ }
+
+ virtual type_t type() const { return type_button; };
+
+private:
+ Led _led;
+};
+
+class LedRing : public Led
+{
+public:
+ LedRing( int id, int ordinal, std::string name, Group & group )
+ : Led( id, ordinal, name, group )
+ {
+ }
+
+ virtual type_t type() const { return type_led_ring; }
+};
+
+class Pot : public Control
+{
+public:
+ Pot( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ , _led_ring( id, ordinal, name + "_ring", group )
+ {
+ }
+
+ virtual type_t type() const { return type_pot; }
+
+ virtual const LedRing & led_ring() const
+ {
+ return _led_ring;
+ }
+
+private:
+ LedRing _led_ring;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/interface.cc b/libs/surfaces/mackie/interface.cc
new file mode 100644
index 0000000000..eda485b5d6
--- /dev/null
+++ b/libs/surfaces/mackie/interface.cc
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2006,2007 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 <control_protocol/control_protocol.h>
+#include "mackie_control_protocol.h"
+
+#include <pbd/error.h>
+
+#include <stdexcept>
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace std;
+
+ControlProtocol*
+new_mackie_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ if ( Config->get_mmc_port_name().substr(0,3) == "mcu" )
+ {
+ error << "mcu already used as mmc port" << endmsg;
+ }
+ else if ( Config->get_mtc_port_name().substr(0,3) == "mcu" )
+ {
+ error << "mcu already used as mtc port" << endmsg;
+ }
+ else if ( Config->get_midi_port_name().substr(0,3) == "mcu" )
+ {
+ error << "mcu already used as midi port" << endmsg;
+ }
+ else
+ {
+ // no one else is using the port, so try instantiate the object
+ MackieControlProtocol * mcp = 0;
+ try
+ {
+ mcp = new MackieControlProtocol (*s);
+ mcp->set_active( true );
+ }
+ catch( exception & e )
+ {
+ error << "Error instantiating MackieControlProtocol: " << e.what() << endmsg;
+ delete mcp;
+ mcp = 0;
+ }
+ return mcp;
+ }
+ return 0;
+}
+
+void
+delete_mackie_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+bool
+probe_mackie_protocol (ControlProtocolDescriptor* descriptor)
+{
+ return MackieControlProtocol::probe();
+}
+
+static ControlProtocolDescriptor mackie_descriptor = {
+ name : "Mackie",
+ id : "uri://ardour.org/surfaces/mackie:0",
+ ptr : 0,
+ module : 0,
+ mandatory : 0,
+ supports_feedback : true,
+ probe : probe_mackie_protocol,
+ initialize : new_mackie_protocol,
+ destroy : delete_mackie_protocol
+};
+
+
+extern "C" {
+
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &mackie_descriptor;
+}
+
+}
diff --git a/libs/surfaces/mackie/mackie_button_handler.cc b/libs/surfaces/mackie/mackie_button_handler.cc
new file mode 100644
index 0000000000..f7ac2ab6d5
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_button_handler.cc
@@ -0,0 +1,691 @@
+/*
+ Generated by scripts/generate-button-handlers.erb
+*/
+#include "mackie_button_handler.h"
+#include "controls.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace Mackie;
+
+LedState MackieButtonHandler::default_button_press( Button & button )
+{
+ cout << "press: " << button << endl;
+ return on;
+}
+LedState MackieButtonHandler::default_button_release( Button & button )
+{
+ cout << "release: " << button << endl;
+ return off;
+}
+
+LedState MackieButtonHandler::io_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::io_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::sends_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::sends_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::pan_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::pan_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::plugin_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::plugin_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::eq_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::eq_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::dyn_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::dyn_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::channel_left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::channel_left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::channel_right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::channel_right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::flip_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::flip_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::edit_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::edit_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::name_value_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::name_value_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::smpte_beats_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::smpte_beats_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F1_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F1_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F2_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F2_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F3_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F3_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F4_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F4_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F5_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F5_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F6_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F6_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F7_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F7_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F8_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F8_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F9_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F9_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F10_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F10_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F11_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F11_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F12_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F12_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F13_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F13_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F14_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F14_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F15_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F15_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F16_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F16_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::shift_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::shift_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::option_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::option_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::control_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::control_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cmd_alt_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cmd_alt_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::on_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::on_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::rec_ready_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::rec_ready_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::undo_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::undo_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::snapshot_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::snapshot_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::touch_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::touch_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::redo_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::redo_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::marker_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::marker_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::enter_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::enter_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cancel_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cancel_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::mixer_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::mixer_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::frm_left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::frm_left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::frm_right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::frm_right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::loop_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::loop_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::punch_in_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::punch_in_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::punch_out_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::punch_out_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::home_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::home_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::end_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::end_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::rewind_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::rewind_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::ffwd_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::ffwd_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::stop_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::stop_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::play_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::play_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::record_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::record_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_up_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_up_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_down_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_down_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::zoom_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::zoom_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::scrub_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::scrub_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::user_a_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::user_a_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::user_b_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::user_b_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::fader_touch_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::fader_touch_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::clicking_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::clicking_release( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::global_solo_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::global_solo_release( Button & button )
+{
+ return default_button_press( button );
+}
diff --git a/libs/surfaces/mackie/mackie_button_handler.h b/libs/surfaces/mackie/mackie_button_handler.h
new file mode 100644
index 0000000000..ee4187c7ce
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_button_handler.h
@@ -0,0 +1,227 @@
+#ifndef mackie_button_handler_h
+#define mackie_button_handler_h
+/*
+ Generated by scripts/generate-button-handlers.erb
+*/
+
+#include "types.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler
+{
+public:
+ virtual ~MackieButtonHandler() {}
+
+ virtual LedState default_button_press( Button & button );
+ virtual LedState default_button_release( Button & button );
+
+ virtual void update_led( Button & button, LedState ls ) = 0;
+
+
+ virtual LedState io_press( Button & );
+ virtual LedState io_release( Button & );
+
+ virtual LedState sends_press( Button & );
+ virtual LedState sends_release( Button & );
+
+ virtual LedState pan_press( Button & );
+ virtual LedState pan_release( Button & );
+
+ virtual LedState plugin_press( Button & );
+ virtual LedState plugin_release( Button & );
+
+ virtual LedState eq_press( Button & );
+ virtual LedState eq_release( Button & );
+
+ virtual LedState dyn_press( Button & );
+ virtual LedState dyn_release( Button & );
+
+ virtual LedState left_press( Button & );
+ virtual LedState left_release( Button & );
+
+ virtual LedState right_press( Button & );
+ virtual LedState right_release( Button & );
+
+ virtual LedState channel_left_press( Button & );
+ virtual LedState channel_left_release( Button & );
+
+ virtual LedState channel_right_press( Button & );
+ virtual LedState channel_right_release( Button & );
+
+ virtual LedState flip_press( Button & );
+ virtual LedState flip_release( Button & );
+
+ virtual LedState edit_press( Button & );
+ virtual LedState edit_release( Button & );
+
+ virtual LedState name_value_press( Button & );
+ virtual LedState name_value_release( Button & );
+
+ virtual LedState smpte_beats_press( Button & );
+ virtual LedState smpte_beats_release( Button & );
+
+ virtual LedState F1_press( Button & );
+ virtual LedState F1_release( Button & );
+
+ virtual LedState F2_press( Button & );
+ virtual LedState F2_release( Button & );
+
+ virtual LedState F3_press( Button & );
+ virtual LedState F3_release( Button & );
+
+ virtual LedState F4_press( Button & );
+ virtual LedState F4_release( Button & );
+
+ virtual LedState F5_press( Button & );
+ virtual LedState F5_release( Button & );
+
+ virtual LedState F6_press( Button & );
+ virtual LedState F6_release( Button & );
+
+ virtual LedState F7_press( Button & );
+ virtual LedState F7_release( Button & );
+
+ virtual LedState F8_press( Button & );
+ virtual LedState F8_release( Button & );
+
+ virtual LedState F9_press( Button & );
+ virtual LedState F9_release( Button & );
+
+ virtual LedState F10_press( Button & );
+ virtual LedState F10_release( Button & );
+
+ virtual LedState F11_press( Button & );
+ virtual LedState F11_release( Button & );
+
+ virtual LedState F12_press( Button & );
+ virtual LedState F12_release( Button & );
+
+ virtual LedState F13_press( Button & );
+ virtual LedState F13_release( Button & );
+
+ virtual LedState F14_press( Button & );
+ virtual LedState F14_release( Button & );
+
+ virtual LedState F15_press( Button & );
+ virtual LedState F15_release( Button & );
+
+ virtual LedState F16_press( Button & );
+ virtual LedState F16_release( Button & );
+
+ virtual LedState shift_press( Button & );
+ virtual LedState shift_release( Button & );
+
+ virtual LedState option_press( Button & );
+ virtual LedState option_release( Button & );
+
+ virtual LedState control_press( Button & );
+ virtual LedState control_release( Button & );
+
+ virtual LedState cmd_alt_press( Button & );
+ virtual LedState cmd_alt_release( Button & );
+
+ virtual LedState on_press( Button & );
+ virtual LedState on_release( Button & );
+
+ virtual LedState rec_ready_press( Button & );
+ virtual LedState rec_ready_release( Button & );
+
+ virtual LedState undo_press( Button & );
+ virtual LedState undo_release( Button & );
+
+ virtual LedState snapshot_press( Button & );
+ virtual LedState snapshot_release( Button & );
+
+ virtual LedState touch_press( Button & );
+ virtual LedState touch_release( Button & );
+
+ virtual LedState redo_press( Button & );
+ virtual LedState redo_release( Button & );
+
+ virtual LedState marker_press( Button & );
+ virtual LedState marker_release( Button & );
+
+ virtual LedState enter_press( Button & );
+ virtual LedState enter_release( Button & );
+
+ virtual LedState cancel_press( Button & );
+ virtual LedState cancel_release( Button & );
+
+ virtual LedState mixer_press( Button & );
+ virtual LedState mixer_release( Button & );
+
+ virtual LedState frm_left_press( Button & );
+ virtual LedState frm_left_release( Button & );
+
+ virtual LedState frm_right_press( Button & );
+ virtual LedState frm_right_release( Button & );
+
+ virtual LedState loop_press( Button & );
+ virtual LedState loop_release( Button & );
+
+ virtual LedState punch_in_press( Button & );
+ virtual LedState punch_in_release( Button & );
+
+ virtual LedState punch_out_press( Button & );
+ virtual LedState punch_out_release( Button & );
+
+ virtual LedState home_press( Button & );
+ virtual LedState home_release( Button & );
+
+ virtual LedState end_press( Button & );
+ virtual LedState end_release( Button & );
+
+ virtual LedState rewind_press( Button & );
+ virtual LedState rewind_release( Button & );
+
+ virtual LedState ffwd_press( Button & );
+ virtual LedState ffwd_release( Button & );
+
+ virtual LedState stop_press( Button & );
+ virtual LedState stop_release( Button & );
+
+ virtual LedState play_press( Button & );
+ virtual LedState play_release( Button & );
+
+ virtual LedState record_press( Button & );
+ virtual LedState record_release( Button & );
+
+ virtual LedState cursor_up_press( Button & );
+ virtual LedState cursor_up_release( Button & );
+
+ virtual LedState cursor_down_press( Button & );
+ virtual LedState cursor_down_release( Button & );
+
+ virtual LedState cursor_left_press( Button & );
+ virtual LedState cursor_left_release( Button & );
+
+ virtual LedState cursor_right_press( Button & );
+ virtual LedState cursor_right_release( Button & );
+
+ virtual LedState zoom_press( Button & );
+ virtual LedState zoom_release( Button & );
+
+ virtual LedState scrub_press( Button & );
+ virtual LedState scrub_release( Button & );
+
+ virtual LedState user_a_press( Button & );
+ virtual LedState user_a_release( Button & );
+
+ virtual LedState user_b_press( Button & );
+ virtual LedState user_b_release( Button & );
+
+ virtual LedState fader_touch_press( Button & );
+ virtual LedState fader_touch_release( Button & );
+
+ virtual LedState clicking_press( Button & );
+ virtual LedState clicking_release( Button & );
+
+ virtual LedState global_solo_press( Button & );
+ virtual LedState global_solo_release( Button & );
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_control_exception.h b/libs/surfaces/mackie/mackie_control_exception.h
new file mode 100644
index 0000000000..afe7016948
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_exception.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 mackie_control_exception_h
+#define mackie_control_exception_h
+
+#include <stdexcept>
+
+namespace Mackie
+{
+
+class MackieControlException : public std::exception
+{
+public:
+ MackieControlException( const std::string & msg )
+ : _msg( msg )
+ {
+ }
+
+ virtual ~MackieControlException() throw () {}
+
+ const char * what() const throw ()
+ {
+ return _msg.c_str();
+ }
+
+private:
+ std::string _msg;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
new file mode 100644
index 0000000000..81d249588e
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -0,0 +1,1378 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 <iostream>
+#include <algorithm>
+#include <cmath>
+#include <sstream>
+#include <vector>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <poll.h>
+
+#include <boost/shared_array.hpp>
+
+#include <midi++/types.h>
+#include <midi++/port.h>
+#include <midi++/manager.h>
+#include <pbd/pthread_utils.h>
+#include <pbd/error.h>
+
+#include <ardour/route.h>
+#include <ardour/session.h>
+#include <ardour/location.h>
+#include <ardour/dB.h>
+#include <ardour/panner.h>
+
+#include "mackie_control_protocol.h"
+
+#include "midi_byte_array.h"
+#include "mackie_control_exception.h"
+#include "route_signal.h"
+#include "mackie_midi_builder.h"
+#include "surface_port.h"
+#include "surface.h"
+#include "bcf_surface.h"
+#include "mackie_surface.h"
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace Mackie;
+using namespace PBD;
+
+using boost::shared_ptr;
+
+#include "i18n.h"
+
+MackieMidiBuilder builder;
+
+// Copied from tranzport_control_protocol.cc
+static inline double
+gain_to_slider_position (ARDOUR::gain_t g)
+{
+ if (g == 0) return 0;
+ return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
+}
+
+/*
+ Copied from tranzport_control_protocol.cc
+ TODO this seems to return slightly wrong values, namely
+ with the UI slider at max, we get a 0.99something value.
+*/
+static inline ARDOUR::gain_t
+slider_position_to_gain (double pos)
+{
+ /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
+ if (pos == 0.0) return 0;
+ return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
+}
+
+MackieControlProtocol::MackieControlProtocol (Session& session)
+ : ControlProtocol (session, X_("Mackie"))
+ , _current_initial_bank( 0 )
+ , connections_back( _connections )
+ , _surface( 0 )
+ , _ports_changed( false )
+ , _polling( true )
+ , pfd( 0 )
+ , nfds( 0 )
+{
+ //cout << "MackieControlProtocol::MackieControlProtocol" << endl;
+ // will start reading from ports, as soon as there are some
+ pthread_create_and_store (X_("mackie monitor"), &thread, 0, _monitor_work, this);
+}
+
+MackieControlProtocol::~MackieControlProtocol()
+{
+ //cout << "~MackieControlProtocol::MackieControlProtocol" << endl;
+ try
+ {
+ close();
+ }
+ catch ( exception & e )
+ {
+ cout << "~MackieControlProtocol caught " << e.what() << endl;
+ }
+ catch ( ... )
+ {
+ cout << "~MackieControlProtocol caught unknown" << endl;
+ }
+ //cout << "finished ~MackieControlProtocol::MackieControlProtocol" << endl;
+}
+
+Mackie::Surface & MackieControlProtocol::surface()
+{
+ if ( _surface == 0 )
+ {
+ throw MackieControlException( "_surface is 0 in MackieControlProtocol::surface" );
+ }
+ return *_surface;
+}
+
+const Mackie::MackiePort & MackieControlProtocol::mcu_port() const
+{
+ return dynamic_cast<const MackiePort &>( *_ports[0] );
+}
+
+Mackie::MackiePort & MackieControlProtocol::mcu_port()
+{
+ return dynamic_cast<const MackiePort &>( *_ports[0] );
+}
+
+// go to the previous track.
+// Assume that get_sorted_routes().size() > route_table.size()
+void MackieControlProtocol::prev_track()
+{
+ if ( _current_initial_bank >= 1 )
+ {
+ session->set_dirty();
+ switch_banks( _current_initial_bank - 1 );
+ }
+}
+
+// go to the next track.
+// Assume that get_sorted_routes().size() > route_table.size()
+void MackieControlProtocol::next_track()
+{
+ Sorted sorted = get_sorted_routes();
+ if ( _current_initial_bank + route_table.size() < sorted.size() )
+ {
+ session->set_dirty();
+ switch_banks( _current_initial_bank + 1 );
+ }
+}
+
+void MackieControlProtocol::clear_route_signals()
+{
+ for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it )
+ {
+ delete *it;
+ }
+ route_signals.clear();
+}
+
+// return the port for a given id - 0 based
+// throws an exception if no port found
+MackiePort & MackieControlProtocol::port_for_id( uint32_t index )
+{
+ uint32_t current_max = 0;
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ current_max += (*it)->strips();
+ if ( index < current_max ) return **it;
+ }
+
+ // oops - no matching port
+ ostringstream os;
+ os << "No port for index " << index;
+ throw MackieControlException( os.str() );
+}
+
+// predicate for sort call in get_sorted_routes
+struct RouteByRemoteId
+{
+ bool operator () ( const shared_ptr<Route> & a, const shared_ptr<Route> & b ) const
+ {
+ return a->remote_control_id() < b->remote_control_id();
+ }
+
+ bool operator () ( const Route & a, const Route & b ) const
+ {
+ return a.remote_control_id() < b.remote_control_id();
+ }
+
+ bool operator () ( const Route * a, const Route * b ) const
+ {
+ return a->remote_control_id() < b->remote_control_id();
+ }
+};
+
+MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
+{
+ Sorted sorted;
+
+ // fetch all routes
+ boost::shared_ptr<Session::RouteList> routes = session->get_routes();
+ set<uint32_t> remote_ids;
+
+ // routes with remote_id 0 should never be added
+ // TODO verify this with ardour devs
+ // remote_ids.insert( 0 );
+
+ // sort in remote_id order, and exclude master, control and hidden routes
+ // and any routes that are already set.
+ for ( Session::RouteList::iterator it = routes->begin(); it != routes->end(); ++it )
+ {
+ Route & route = **it;
+ if (
+ route.active()
+ && !route.master()
+ && !route.hidden()
+ && !route.control()
+ && remote_ids.find( route.remote_control_id() ) == remote_ids.end()
+ )
+ {
+ sorted.push_back( *it );
+ remote_ids.insert( route.remote_control_id() );
+ }
+ }
+ sort( sorted.begin(), sorted.end(), RouteByRemoteId() );
+ return sorted;
+}
+
+void MackieControlProtocol::refresh_current_bank()
+{
+ switch_banks( _current_initial_bank );
+}
+
+void MackieControlProtocol::switch_banks( int initial )
+{
+ // DON'T prevent bank switch if initial == _current_initial_bank
+ // because then this method can't be used as a refresh
+
+ // sanity checking
+ Sorted sorted = get_sorted_routes();
+ int delta = sorted.size() - route_table.size();
+ if ( initial < 0 || ( delta > 0 && initial > delta ) )
+ {
+ cout << "not switching to " << initial << endl;
+ return;
+ }
+ _current_initial_bank = initial;
+
+ // first clear the signals from old routes
+ // taken care of by the RouteSignal destructors
+ clear_route_signals();
+
+ // now set the signals for new routes
+ if ( _current_initial_bank <= sorted.size() )
+ {
+ // fetch the bank start and end to switch to
+ uint32_t end_pos = min( route_table.size(), sorted.size() );
+ Sorted::iterator it = sorted.begin() + _current_initial_bank;
+ Sorted::iterator end = sorted.begin() + _current_initial_bank + end_pos;
+ //cout << "switch to " << _current_initial_bank << ", " << end_pos << endl;
+
+ // link routes to strips
+ uint32_t i = 0;
+ for ( ; it != end && it != sorted.end(); ++it, ++i )
+ {
+ boost::shared_ptr<Route> route = *it;
+ Strip & strip = *surface().strips[i];
+ //cout << "remote id " << route->remote_control_id() << " connecting " << route->name() << " to " << strip.name() << " with port " << port_for_id(i) << endl;
+ route_table[i] = route;
+ RouteSignal * rs = new RouteSignal( *route, *this, strip, port_for_id(i) );
+ route_signals.push_back( rs );
+ // update strip from route
+ rs->notify_all();
+ }
+
+ // create dead strips if there aren't enough routes to
+ // fill a bank
+ for ( ; i < route_table.size(); ++i )
+ {
+ Strip & strip = *surface().strips[i];
+ // send zero for this strip
+ port_for_id(i).write( builder.zero_strip( strip ) );
+ }
+ }
+
+ // display the current start bank.
+ if ( mcu_port().emulation() == MackiePort::bcf2000 )
+ {
+ if ( _current_initial_bank == 0 )
+ {
+ // send Ar. to 2-char display on the master
+ mcu_port().write( builder.two_char_display( "Ar", ".." ) );
+ }
+ else
+ {
+ // write the current first remote_id to the 2-char display
+ mcu_port().write( builder.two_char_display( _current_initial_bank ) );
+ }
+ }
+}
+
+void MackieControlProtocol::zero_all()
+{
+ // TODO turn off 55-char and SMPTE displays
+
+ if ( mcu_port().emulation() == MackiePort::bcf2000 )
+ {
+ // clear 2-char display
+ mcu_port().write( builder.two_char_display( "LC" ) );
+ }
+
+ // zero all strips
+ for ( Surface::Strips::iterator it = surface().strips.begin(); it != surface().strips.end(); ++it )
+ {
+ port_for_id( (*it)->index() ).write( builder.zero_strip( **it ) );
+ }
+
+ // and the master strip
+ mcu_port().write( builder.zero_strip( master_strip() ) );
+
+ // and the led ring for the master strip, in bcf mode
+ if ( mcu_port().emulation() == MackiePort::bcf2000 )
+ {
+ Control & control = *surface().controls_by_name["jog"];
+ mcu_port().write( builder.build_led_ring( dynamic_cast<Pot &>( control ), off ) );
+ }
+
+ // turn off global buttons and leds
+ // global buttons are only ever on mcu_port, so we don't have
+ // to figure out which port.
+ for ( Surface::Controls::iterator it = surface().controls.begin(); it != surface().controls.end(); ++it )
+ {
+ Control & control = **it;
+ if ( !control.group().is_strip() && control.accepts_feedback() )
+ {
+ mcu_port().write( builder.zero_control( control ) );
+ }
+ }
+}
+
+int MackieControlProtocol::set_active (bool yn)
+{
+ if ( yn != _active )
+ {
+ try
+ {
+ // the reason for the locking and unlocking is that
+ // glibmm can't do a condition wait on a RecMutex
+ if ( yn )
+ {
+ // TODO what happens if this fails half way?
+
+ // create MackiePorts
+ {
+ Glib::Mutex::Lock lock( update_mutex );
+ create_ports();
+ }
+
+ // make sure the ports are being listened to
+ update_ports();
+
+ // wait until poll thread is running, with ports to poll
+ // the mutex is only there because conditions require a mutex
+ {
+ Glib::Mutex::Lock lock( update_mutex );
+ while ( nfds == 0 ) update_cond.wait( update_mutex );
+ }
+
+ // now initialise MackiePorts - ie exchange sysex messages
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ (*it)->open();
+ }
+
+ // wait until all ports are active
+ // TODO a more sophisticated approach would
+ // allow things to start up with only an MCU, even if
+ // extenders were specified but not responding.
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ (*it)->wait_for_init();
+ }
+
+ // create surface object. This depends on the ports being
+ // correctly initialised
+ initialize_surface();
+ connect_session_signals();
+
+ // yeehah!
+ _active = true;
+
+ // send current control positions to surface
+ // must come after _active = true otherwise it won't run
+ update_surface();
+ }
+ else
+ {
+ close();
+ _active = false;
+ }
+ }
+ catch( exception & e )
+ {
+ cout << "set_active to false because exception caught: " << e.what() << endl;
+ _active = false;
+ throw;
+ }
+ }
+
+ return 0;
+}
+
+bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState bs, boost::shared_ptr<Route> route )
+{
+ bool state = false;
+
+ if ( bs == press )
+ {
+ if ( control.name() == "recenable" )
+ {
+ state = !route->record_enabled();
+ route->set_record_enable( state, this );
+ }
+ else if ( control.name() == "mute" )
+ {
+ state = !route->muted();
+ route->set_mute( state, this );
+ }
+ else if ( control.name() == "solo" )
+ {
+ state = !route->soloed();
+ route->set_solo( state, this );
+ }
+ else if ( control.name() == "select" )
+ {
+ // TODO make the track selected. Whatever that means.
+ //state = default_button_press( dynamic_cast<Button&>( control ) );
+ }
+ else if ( control.name() == "vselect" )
+ {
+ // TODO could be used to select different things to apply the pot to?
+ //state = default_button_press( dynamic_cast<Button&>( control ) );
+ }
+ }
+
+ if ( control.name() == "fader_touch" )
+ {
+ state = bs == press;
+ control.strip().gain().touch( state );
+ }
+
+ return state;
+}
+
+void MackieControlProtocol::update_led( Mackie::Button & button, Mackie::LedState ls )
+{
+ MackiePort * port = 0;
+ if ( button.group().is_strip() )
+ {
+ if ( button.group().is_master() )
+ {
+ port = &mcu_port();
+ }
+ else
+ {
+ port = &port_for_id( dynamic_cast<const Strip&>( button.group() ).index() );
+ }
+ }
+ else
+ {
+ port = &mcu_port();
+ }
+ if ( ls != none ) port->write( builder.build_led( button, ls ) );
+}
+
+void MackieControlProtocol::update_global_button( const string & name, LedState ls )
+{
+ if ( surface().controls_by_name.find( name ) !=surface().controls_by_name.end() )
+ {
+ Button * button = dynamic_cast<Button*>( surface().controls_by_name[name] );
+ mcu_port().write( builder.build_led( button->led(), ls ) );
+ }
+ else
+ {
+ cout << "Button " << name << " not found" << endl;
+ }
+}
+
+// send messages to surface to set controls to correct values
+void MackieControlProtocol::update_surface()
+{
+ if ( _active )
+ {
+ // do the initial bank switch to connect signals
+ // _current_initial_bank is initialised by set_state
+ switch_banks( _current_initial_bank );
+
+ // create a RouteSignal for the master route
+ // but only the first time around
+ master_route_signal = shared_ptr<RouteSignal>( new RouteSignal( *master_route(), *this, master_strip(), mcu_port() ) );
+ // update strip from route
+ master_route_signal->notify_all();
+
+ // update global buttons and displays
+ notify_record_state_changed();
+ notify_transport_state_changed();
+ }
+}
+
+void MackieControlProtocol::connect_session_signals()
+{
+ // receive routes added
+ connections_back = session->RouteAdded.connect( ( mem_fun (*this, &MackieControlProtocol::notify_route_added) ) );
+ // receive record state toggled
+ connections_back = session->RecordStateChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_record_state_changed) ) );
+ // receive transport state changed
+ connections_back = session->TransportStateChange.connect( ( mem_fun (*this, &MackieControlProtocol::notify_transport_state_changed) ) );
+ // receive punch-in and punch-out
+ connections_back = Config->ParameterChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_parameter_changed) ) );
+ // receive rude solo changed
+ connections_back = session->SoloActive.connect( ( mem_fun (*this, &MackieControlProtocol::notify_solo_active_changed) ) );
+
+ // make sure remote id changed signals reach here
+ // see also notify_route_added
+ Sorted sorted = get_sorted_routes();
+ for ( Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it )
+ {
+ connections_back = (*it)->RemoteControlIDChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_remote_id_changed) ) );
+ }
+}
+
+void MackieControlProtocol::add_port( MIDI::Port & midi_port, int number )
+{
+ MackiePort * sport = new MackiePort( *this, midi_port, number );
+ _ports.push_back( sport );
+
+ connections_back = sport->init_event.connect(
+ sigc::bind (
+ mem_fun (*this, &MackieControlProtocol::handle_port_init)
+ , sport
+ )
+ );
+
+ connections_back = sport->active_event.connect(
+ sigc::bind (
+ mem_fun (*this, &MackieControlProtocol::handle_port_active)
+ , sport
+ )
+ );
+
+ connections_back = sport->inactive_event.connect(
+ sigc::bind (
+ mem_fun (*this, &MackieControlProtocol::handle_port_inactive)
+ , sport
+ )
+ );
+
+ _ports_changed = true;
+}
+
+void MackieControlProtocol::create_ports()
+{
+ MIDI::Manager * mm = MIDI::Manager::instance();
+
+ // open main port
+ {
+ MIDI::Port * midi_port = mm->port( default_port_name );
+
+ if ( midi_port == 0 ) {
+ ostringstream os;
+ os << string_compose( _("no MIDI port named \"%1\" exists - Mackie control disabled"), default_port_name );
+ error << os.str() << endmsg;
+ throw MackieControlException( os.str() );
+ }
+ add_port( *midi_port, 0 );
+ }
+
+ // open extender ports. Up to 9. Should be enough.
+ // could also use mm->get_midi_ports()
+ string ext_port_base = "mcu_xt_";
+ for ( int index = 1; index <= 9; ++index )
+ {
+ ostringstream os;
+ os << ext_port_base << index;
+ MIDI::Port * midi_port = mm->port( os.str() );
+ if ( midi_port != 0 ) add_port( *midi_port, index );
+ }
+}
+
+shared_ptr<Route> MackieControlProtocol::master_route()
+{
+ shared_ptr<Route> retval;
+ retval = session->route_by_name( "master" );
+ if ( retval == 0 )
+ {
+ // TODO search through all routes for one with the master attribute set
+ }
+ return retval;
+}
+
+Strip & MackieControlProtocol::master_strip()
+{
+ return dynamic_cast<Strip&>( *surface().groups["master"] );
+}
+
+void MackieControlProtocol::initialize_surface()
+{
+ // set up the route table
+ int strips = 0;
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ strips += (*it)->strips();
+ }
+
+ set_route_table_size( strips );
+
+ switch ( mcu_port().emulation() )
+ {
+ case MackiePort::bcf2000: _surface = new BcfSurface( strips ); break;
+ case MackiePort::mackie: _surface = new MackieSurface( strips ); break;
+ default:
+ ostringstream os;
+ os << "no Surface class found for emulation: " << mcu_port().emulation();
+ throw MackieControlException( os.str() );
+ }
+ _surface->init();
+
+ // Connect events. Must be after route table otherwise there will be trouble
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ connections_back = (*it)->control_event.connect( ( mem_fun (*this, &MackieControlProtocol::handle_control_event) ) );
+ }
+}
+
+void MackieControlProtocol::close()
+{
+ // TODO disconnect port active/inactive signals
+ // Or at least put a lock here
+
+ // disconnect global signals from Session
+ // TODO Since *this is a sigc::trackable, this shouldn't be necessary
+ // but it is for some reason
+#if 0
+ for( vector<sigc::connection>::iterator it = _connections.begin(); it != _connections.end(); ++it )
+ {
+ it->disconnect();
+ }
+#endif
+
+ if ( _surface != 0 )
+ {
+ // These will fail if the port has gone away.
+ // So catch the exception and do the rest of the
+ // close afterwards
+ // because the bcf doesn't respond to the next 3 sysex messages
+ try
+ {
+ zero_all();
+ }
+ catch ( exception & e )
+ {
+ cout << "MackieControlProtocol::close caught exception: " << e.what() << endl;
+ }
+
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ try
+ {
+ MackiePort & port = **it;
+ // faders to minimum
+ port.write_sysex( 0x61 );
+ // All LEDs off
+ port.write_sysex( 0x62 );
+ // Reset (reboot into offline mode)
+ port.write_sysex( 0x63 );
+ }
+ catch ( exception & e )
+ {
+ cout << "MackieControlProtocol::close caught exception: " << e.what() << endl;
+ }
+ }
+
+ // disconnect routes from strips
+ clear_route_signals();
+
+ delete _surface;
+ _surface = 0;
+ }
+
+ // stop polling, and wait for it...
+ _polling = false;
+ pthread_join( thread, 0 );
+
+ // shut down MackiePorts
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ delete *it;
+ }
+ _ports.clear();
+
+ // this is done already in monitor_work. But it's here so we know.
+ delete[] pfd;
+ pfd = 0;
+ nfds = 0;
+}
+
+void* MackieControlProtocol::_monitor_work (void* arg)
+{
+ return static_cast<MackieControlProtocol*>(arg)->monitor_work ();
+}
+
+XMLNode & MackieControlProtocol::get_state()
+{
+ //cout << "MackieControlProtocol::get_state" << endl;
+
+ // add name of protocol
+ XMLNode* node = new XMLNode( X_("Protocol") );
+ node->add_property( X_("name"), _name );
+
+ // add current bank
+ ostringstream os;
+ os << _current_initial_bank;
+ node->add_property( X_("bank"), os.str() );
+
+ return *node;
+}
+
+int MackieControlProtocol::set_state( const XMLNode & node )
+{
+ //cout << "MackieControlProtocol::set_state: active " << _active << endl;
+ int retval = 0;
+
+ // fetch current bank
+ if ( node.property( X_("bank") ) != 0 )
+ {
+ string bank = node.property( X_("bank") )->value();
+ try
+ {
+ set_active( true );
+ uint32_t new_bank = atoi( bank.c_str() );
+ if ( _current_initial_bank != new_bank ) switch_banks( new_bank );
+ }
+ catch ( exception & e )
+ {
+ cout << "exception in MackieControlProtocol::set_state: " << e.what() << endl;
+ return -1;
+ }
+ }
+
+ return retval;
+}
+
+void MackieControlProtocol::handle_control_event( SurfacePort & port, Control & control, const ControlState & state )
+{
+ uint32_t index = control.ordinal() - 1 + ( port.number() * port.strips() );
+ boost::shared_ptr<Route> route;
+ if ( control.group().is_strip() )
+ {
+ if ( control.group().is_master() )
+ {
+ route = master_route();
+ }
+ else if ( index < route_table.size() )
+ route = route_table[index];
+ else
+ cerr << "Warning: index is " << index << " which is not in the route table, size: " << route_table.size() << endl;
+ }
+
+ // This handles control element events from the surface
+ // the state of the controls on the surface is usually updated
+ // from UI events.
+ switch ( control.type() )
+ {
+ case Control::type_fader:
+ if ( control.group().is_strip() )
+ {
+ // find the route in the route table for the id
+ // if the route isn't available, skip it
+ // at which point the fader should just reset itself
+ if ( route != 0 )
+ {
+ route->set_gain( slider_position_to_gain( state.pos ), this );
+
+ // must echo bytes back to slider now, because
+ // the notifier only works if the fader is not being
+ // touched. Which it is if we're getting input.
+ port.write( builder.build_fader( (Fader&)control, state.pos ) );
+ }
+ }
+ else
+ {
+ // master fader
+ boost::shared_ptr<Route> route = master_route();
+ if ( route )
+ {
+ route->set_gain( slider_position_to_gain( state.pos ), this );
+ port.write( builder.build_fader( (Fader&)control, state.pos ) );
+ }
+ }
+ break;
+
+ case Control::type_button:
+ if ( control.group().is_strip() )
+ {
+ // strips
+ if ( route != 0 )
+ {
+ handle_strip_button( control, state.button_state, route );
+ }
+ else
+ {
+ // no route so always switch the light off
+ // because no signals will be emitted by a non-route
+ port.write( builder.build_led( control.led(), off ) );
+ }
+ }
+ else if ( control.group().is_master() )
+ {
+ // master fader touch
+ boost::shared_ptr<Route> route = master_route();
+ if ( route )
+ handle_strip_button( control, state.button_state, route );
+ }
+ else
+ {
+ // handle all non-strip buttons
+ surface().handle_button( *this, state.button_state, dynamic_cast<Button&>( control ) );
+ }
+ break;
+
+ // pot (jog wheel, external control)
+ case Control::type_pot:
+ if ( control.group().is_strip() )
+ {
+ if ( route != 0 )
+ {
+ if ( route->panner().size() == 1 )
+ {
+ // assume pan for now
+ float xpos;
+ route->panner()[0]->get_effective_position (xpos);
+
+ // calculate new value, and trim
+ xpos += state.delta;
+ if ( xpos > 1.0 )
+ xpos = 1.0;
+ else if ( xpos < 0.0 )
+ xpos = 0.0;
+
+ route->panner()[0]->set_position( xpos );
+ }
+ }
+ else
+ {
+ // it's a pot for an umnapped route, so turn all the lights off
+ port.write( builder.build_led_ring( dynamic_cast<Pot &>( control ), off ) );
+ }
+ }
+ else
+ {
+ if ( control.name() == "jog" )
+ {
+ // TODO use current snap-to setting?
+ long delta = state.ticks * 1000;
+ nframes_t next = session->transport_frame() + delta;
+ if ( delta < 0 && session->transport_frame() < (nframes_t) abs( delta ) )
+ {
+ next = session->current_start_frame();
+ }
+ else if ( next > session->current_end_frame() )
+ {
+ next = session->current_end_frame();
+ }
+
+ // doesn't work very well
+ session->request_locate( next, session->transport_rolling() );
+
+ // turn off the led ring, for bcf emulation mode
+ port.write( builder.build_led_ring( dynamic_cast<Pot &>( control ), off ) );
+ }
+ else
+ {
+ cout << "external controller" << state.ticks << endl;
+ }
+ }
+ break;
+
+ default:
+ cout << "Control::type not handled: " << control.type() << endl;
+ }
+}
+
+/////////////////////////////////////////////////
+// handlers for Route signals
+// TODO should these be part of RouteSignal?
+// They started off as sigc handlers for signals
+// from Route, but they're also used in polling for automation
+/////////////////////////////////////////////////
+
+void MackieControlProtocol::notify_solo_changed( RouteSignal * route_signal )
+{
+ try
+ {
+ Button & button = route_signal->strip().solo();
+ route_signal->port().write( builder.build_led( button, route_signal->route().soloed() ) );
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+void MackieControlProtocol::notify_mute_changed( RouteSignal * route_signal )
+{
+ try
+ {
+ Button & button = route_signal->strip().mute();
+ route_signal->port().write( builder.build_led( button, route_signal->route().muted() ) );
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+void MackieControlProtocol::notify_record_enable_changed( RouteSignal * route_signal )
+{
+ try
+ {
+ Button & button = route_signal->strip().recenable();
+ route_signal->port().write( builder.build_led( button, route_signal->route().record_enabled() ) );
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+void MackieControlProtocol::notify_gain_changed( RouteSignal * route_signal )
+{
+ try
+ {
+ Fader & fader = route_signal->strip().gain();
+ if ( !fader.touch() )
+ {
+ route_signal->port().write( builder.build_fader( fader, gain_to_slider_position( route_signal->route().effective_gain() ) ) );
+ }
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+void MackieControlProtocol::notify_name_changed( void *, RouteSignal * route_signal )
+{
+ try
+ {
+ // TODO implement MackieControlProtocol::notify_name_changed
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+// TODO deal with > 1 channel being panned
+void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal )
+{
+ try
+ {
+ Pot & pot = route_signal->strip().vpot();
+
+ if ( route_signal->route().panner().size() == 1 )
+ {
+ float pos;
+ route_signal->route().panner()[0]->get_effective_position( pos);
+ route_signal->port().write( builder.build_led_ring( pot, ControlState( on, pos ) ) );
+ }
+ else
+ {
+ route_signal->port().write( builder.zero_control( pot ) );
+ }
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+// TODO handle plugin automation polling
+void MackieControlProtocol::update_automation( RouteSignal & rs )
+{
+ ARDOUR::AutoState gain_state = rs.route().gain_automation_state();
+ if ( gain_state == Touch || gain_state == Play )
+ {
+ notify_gain_changed( &rs );
+ }
+
+ ARDOUR::AutoState panner_state = rs.route().panner().automation_state();
+ if ( panner_state == Touch || panner_state == Play )
+ {
+ notify_panner_changed( &rs );
+ }
+}
+
+void MackieControlProtocol::poll_automation()
+{
+ if ( _active )
+ {
+ // do all currently mapped routes
+ for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it )
+ {
+ update_automation( **it );
+ }
+
+ // and the master strip
+ if ( master_route_signal != 0 ) update_automation( *master_route_signal );
+ }
+}
+
+/////////////////////////////////////
+// Transport Buttons
+/////////////////////////////////////
+
+LedState MackieControlProtocol::rewind_press( Button & button )
+{
+ // can use first_mark_before/after as well
+ Location * loc = session->locations()->first_location_before (
+ session->transport_frame()
+ );
+ if ( loc != 0 ) session->request_locate( loc->start(), session->transport_rolling() );
+ return on;
+}
+
+LedState MackieControlProtocol::rewind_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::ffwd_press( Button & button )
+{
+ // can use first_mark_before/after as well
+ Location * loc = session->locations()->first_location_after (
+ session->transport_frame()
+ );
+ if ( loc != 0 ) session->request_locate( loc->start(), session->transport_rolling() );
+ return on;
+}
+
+LedState MackieControlProtocol::ffwd_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::stop_press( Button & button )
+{
+ session->request_stop();
+ return on;
+}
+
+LedState MackieControlProtocol::stop_release( Button & button )
+{
+ return session->transport_stopped();
+}
+
+LedState MackieControlProtocol::play_press( Button & button )
+{
+ session->request_transport_speed( 1.0 );
+ return on;
+}
+
+LedState MackieControlProtocol::play_release( Button & button )
+{
+ return session->transport_rolling();
+}
+
+LedState MackieControlProtocol::record_press( Button & button )
+{
+ if ( session->get_record_enabled() )
+ session->disable_record( false );
+ else
+ session->maybe_enable_record();
+ return on;
+}
+
+LedState MackieControlProtocol::record_release( Button & button )
+{
+ if ( session->get_record_enabled() )
+ {
+ if ( session->transport_rolling() )
+ return on;
+ else
+ return flashing;
+ }
+ else
+ return off;
+}
+
+///////////////////////////////////////////
+// Session signals
+///////////////////////////////////////////
+
+void MackieControlProtocol::notify_parameter_changed( const char * name_str )
+{
+ string name( name_str );
+ if ( name == "punch-in" )
+ {
+ update_global_button( "punch_in", Config->get_punch_in() );
+ }
+ else if ( name == "punch-out" )
+ {
+ update_global_button( "punch_out", Config->get_punch_out() );
+ }
+ else if ( name == "clicking" )
+ {
+ update_global_button( "clicking", Config->get_clicking() );
+ }
+ else
+ {
+ cout << "parameter changed: " << name << endl;
+ }
+}
+
+// RouteList is the set of routes that have just been added
+void MackieControlProtocol::notify_route_added( ARDOUR::Session::RouteList & rl )
+{
+ // currently assigned banks are less than the full set of
+ // strips, so activate the new strip now.
+ if ( route_signals.size() < route_table.size() )
+ {
+ refresh_current_bank();
+ }
+ // otherwise route added, but current bank needs no updating
+
+ // make sure remote id changes in the new route are handled
+ typedef ARDOUR::Session::RouteList ARS;
+ for ( ARS::iterator it = rl.begin(); it != rl.end(); ++it )
+ {
+ connections_back = (*it)->RemoteControlIDChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_remote_id_changed) ) );
+ }
+}
+
+void MackieControlProtocol::notify_solo_active_changed( bool active )
+{
+ Button * rude_solo = reinterpret_cast<Button*>( surface().controls_by_name["solo"] );
+ mcu_port().write( builder.build_led( *rude_solo, active ? flashing : off ) );
+}
+
+void MackieControlProtocol::notify_remote_id_changed()
+{
+ Sorted sorted = get_sorted_routes();
+
+ // if a remote id has been moved off the end, we need to shift
+ // the current bank backwards.
+ if ( sorted.size() - _current_initial_bank < route_signals.size() )
+ {
+ // but don't shift backwards past the zeroth channel
+ switch_banks( max((Sorted::size_type) 0, sorted.size() - route_signals.size() ) );
+ }
+ // Otherwise just refresh the current bank
+ else
+ {
+ refresh_current_bank();
+ }
+}
+
+///////////////////////////////////////////
+// Transport signals
+///////////////////////////////////////////
+
+void MackieControlProtocol::notify_record_state_changed()
+{
+ // switch rec button on / off / flashing
+ Button * rec = reinterpret_cast<Button*>( surface().controls_by_name["record"] );
+ mcu_port().write( builder.build_led( *rec, record_release( *rec ) ) );
+}
+
+void MackieControlProtocol::notify_transport_state_changed()
+{
+ // switch various play and stop buttons on / off
+ update_global_button( "play", session->transport_rolling() );
+ update_global_button( "stop", !session->transport_rolling() );
+ update_global_button( "loop", session->get_play_loop() );
+
+ // rec is special because it's tristate
+ Button * rec = reinterpret_cast<Button*>( surface().controls_by_name["record"] );
+ mcu_port().write( builder.build_led( *rec, record_release( *rec ) ) );
+}
+
+LedState MackieControlProtocol::loop_press( Button & button )
+{
+ session->request_play_loop( !session->get_play_loop() );
+ return on;
+}
+
+LedState MackieControlProtocol::loop_release( Button & button )
+{
+ return session->get_play_loop();
+}
+
+LedState MackieControlProtocol::punch_in_press( Button & button )
+{
+ bool state = !Config->get_punch_in();
+ Config->set_punch_in( state );
+ return state;
+}
+
+LedState MackieControlProtocol::punch_in_release( Button & button )
+{
+ return Config->get_punch_in();
+}
+
+LedState MackieControlProtocol::punch_out_press( Button & button )
+{
+ bool state = !Config->get_punch_out();
+ Config->set_punch_out( state );
+ return state;
+}
+
+LedState MackieControlProtocol::punch_out_release( Button & button )
+{
+ return Config->get_punch_out();
+}
+
+LedState MackieControlProtocol::home_press( Button & button )
+{
+ session->goto_start();
+ return on;
+}
+
+LedState MackieControlProtocol::home_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::end_press( Button & button )
+{
+ session->goto_end();
+ return on;
+}
+
+LedState MackieControlProtocol::end_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::clicking_press( Button & button )
+{
+ bool state = !Config->get_clicking();
+ Config->set_clicking( state );
+ return state;
+}
+
+LedState MackieControlProtocol::clicking_release( Button & button )
+{
+ return Config->get_clicking();
+}
+
+LedState MackieControlProtocol::global_solo_press( Button & button )
+{
+ bool state = !session->soloing();
+ session->set_all_solo ( state );
+ return state;
+}
+
+LedState MackieControlProtocol::global_solo_release( Button & button )
+{
+ return session->soloing();
+}
+
+/////////////////////////////////////
+// Bank Switching
+/////////////////////////////////////
+LedState MackieControlProtocol::left_press( Button & button )
+{
+ Sorted sorted = get_sorted_routes();
+ if ( sorted.size() > route_table.size() )
+ {
+ int new_initial = _current_initial_bank - route_table.size();
+ if ( new_initial < 0 ) new_initial = 0;
+ if ( new_initial != int( _current_initial_bank ) )
+ {
+ session->set_dirty();
+ switch_banks( new_initial );
+ }
+
+ return on;
+ }
+ else
+ {
+ return flashing;
+ }
+}
+
+LedState MackieControlProtocol::left_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::right_press( Button & button )
+{
+ Sorted sorted = get_sorted_routes();
+ if ( sorted.size() > route_table.size() )
+ {
+ uint32_t delta = sorted.size() - ( route_table.size() + _current_initial_bank );
+ if ( delta > route_table.size() ) delta = route_table.size();
+ if ( delta > 0 )
+ {
+ session->set_dirty();
+ switch_banks( _current_initial_bank + delta );
+ }
+
+ return on;
+ }
+ else
+ {
+ return flashing;
+ }
+}
+
+LedState MackieControlProtocol::right_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::channel_left_press( Button & button )
+{
+ Sorted sorted = get_sorted_routes();
+ if ( sorted.size() > route_table.size() )
+ {
+ prev_track();
+ return on;
+ }
+ else
+ {
+ return flashing;
+ }
+}
+
+LedState MackieControlProtocol::channel_left_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::channel_right_press( Button & button )
+{
+ Sorted sorted = get_sorted_routes();
+ if ( sorted.size() > route_table.size() )
+ {
+ next_track();
+ return on;
+ }
+ else
+ {
+ return flashing;
+ }
+}
+
+LedState MackieControlProtocol::channel_right_release( Button & button )
+{
+ return off;
+}
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
new file mode 100644
index 0000000000..d71979b463
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -0,0 +1,307 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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_mackie_control_protocol_h
+#define ardour_mackie_control_protocol_h
+
+#include <vector>
+
+#include <sys/time.h>
+#include <pthread.h>
+
+#include <glibmm/thread.h>
+
+#include <ardour/types.h>
+#include <ardour/session.h>
+#include <midi++/types.h>
+
+#include <control_protocol/control_protocol.h>
+#include "midi_byte_array.h"
+#include "controls.h"
+#include "route_signal.h"
+#include "mackie_button_handler.h"
+#include "mackie_port.h"
+
+namespace MIDI {
+ class Port;
+ class Parser;
+}
+
+namespace Mackie {
+ class Surface;
+}
+
+/**
+ This handles the plugin duties, and the midi encoding and decoding,
+ and the signal callbacks, mostly from ARDOUR::Route.
+
+ The model of the control surface is handled by classes in controls.h
+
+ What happens is that each strip on the control surface has
+ a corresponding route in ControlProtocol::route_table. When
+ an incoming midi message is signaled, the correct route
+ is looked up, and the relevant changes made to it.
+
+ For each route currently in route_table, there's a RouteSignal object
+ which encapsulates the signals that indicate that there are changes
+ to be sent to the surface. The signals are handled by this class.
+
+ Calls to signal handlers pass a Route object which is used to look
+ up the relevant Strip in Surface. Then the state is retrieved from
+ the Route and encoded as the correct midi message.
+*/
+class MackieControlProtocol
+: public ARDOUR::ControlProtocol
+, public Mackie::MackieButtonHandler
+{
+ public:
+ MackieControlProtocol( ARDOUR::Session & );
+ virtual ~MackieControlProtocol();
+
+ int set_active (bool yn);
+
+ XMLNode& get_state ();
+ int set_state (const XMLNode&);
+
+ static bool probe();
+
+ Mackie::Surface & surface();
+
+ // control events
+ void handle_control_event( Mackie::SurfacePort & port, Mackie::Control & control, const Mackie::ControlState & state );
+
+ // strip/route related stuff
+ public:
+ /// Signal handler for Route::solo
+ void notify_solo_changed( Mackie::RouteSignal * );
+ /// Signal handler for Route::mute
+ void notify_mute_changed( Mackie::RouteSignal * );
+ /// Signal handler for Route::record_enable_changed
+ void notify_record_enable_changed( Mackie::RouteSignal * );
+ /// Signal handler for Route::gain_changed ( from IO )
+ void notify_gain_changed( Mackie::RouteSignal * );
+ /// Signal handler for Route::name_change
+ void notify_name_changed( void *, Mackie::RouteSignal * );
+ /// Signal handler from Panner::Change
+ void notify_panner_changed( Mackie::RouteSignal * );
+ /// Signal handler for new routes added
+ void notify_route_added( ARDOUR::Session::RouteList & );
+
+ void notify_remote_id_changed();
+
+ /// rebuild the current bank. Called on route added/removed and
+ /// remote id changed.
+ void refresh_current_bank();
+
+ // global buttons (ie button not part of strips)
+ public:
+ // button-related signals
+ void notify_record_state_changed();
+ void notify_transport_state_changed();
+ // mainly to pick up punch-in and punch-out
+ void notify_parameter_changed( const char * );
+ void notify_solo_active_changed( bool );
+
+ // this is called to generate the midi to send in response to
+ // a button press.
+ void update_led( Mackie::Button & button, Mackie::LedState );
+
+ // calls update_led, but looks up the button by name
+ void update_global_button( const std::string & name, Mackie::LedState );
+
+ // transport button handler methods from MackieButtonHandler
+ virtual Mackie::LedState rewind_press( Mackie::Button & );
+ virtual Mackie::LedState rewind_release( Mackie::Button & );
+
+ virtual Mackie::LedState ffwd_press( Mackie::Button & );
+ virtual Mackie::LedState ffwd_release( Mackie::Button & );
+
+ virtual Mackie::LedState stop_press( Mackie::Button & );
+ virtual Mackie::LedState stop_release( Mackie::Button & );
+
+ virtual Mackie::LedState play_press( Mackie::Button & );
+ virtual Mackie::LedState play_release( Mackie::Button & );
+
+ virtual Mackie::LedState record_press( Mackie::Button & );
+ virtual Mackie::LedState record_release( Mackie::Button & );
+
+ virtual Mackie::LedState loop_press( Mackie::Button & );
+ virtual Mackie::LedState loop_release( Mackie::Button & );
+
+ virtual Mackie::LedState punch_in_press( Mackie::Button & );
+ virtual Mackie::LedState punch_in_release( Mackie::Button & );
+
+ virtual Mackie::LedState punch_out_press( Mackie::Button & );
+ virtual Mackie::LedState punch_out_release( Mackie::Button & );
+
+ virtual Mackie::LedState home_press( Mackie::Button & );
+ virtual Mackie::LedState home_release( Mackie::Button & );
+
+ virtual Mackie::LedState end_press( Mackie::Button & );
+ virtual Mackie::LedState end_release( Mackie::Button & );
+
+ // bank switching button handler methods from MackieButtonHandler
+ virtual Mackie::LedState left_press( Mackie::Button & );
+ virtual Mackie::LedState left_release( Mackie::Button & );
+
+ virtual Mackie::LedState right_press( Mackie::Button & );
+ virtual Mackie::LedState right_release( Mackie::Button & );
+
+ virtual Mackie::LedState channel_left_press( Mackie::Button & );
+ virtual Mackie::LedState channel_left_release( Mackie::Button & );
+
+ virtual Mackie::LedState channel_right_press( Mackie::Button & );
+ virtual Mackie::LedState channel_right_release( Mackie::Button & );
+
+ virtual Mackie::LedState clicking_press( Mackie::Button & );
+ virtual Mackie::LedState clicking_release( Mackie::Button & );
+
+ virtual Mackie::LedState global_solo_press( Mackie::Button & );
+ virtual Mackie::LedState global_solo_release( Mackie::Button & );
+
+ protected:
+ // create instances of MackiePort, depending on what's found in ardour.rc
+ void create_ports();
+
+ // shut down the surface
+ void close();
+
+ // create the Surface object, with the correct number
+ // of strips for the currently connected ports and
+ // hook up the control event notification
+ void initialize_surface();
+
+ // This sets up the notifications and sets the
+ // controls to the correct values
+ void update_surface();
+
+ // connects global (not strip) signals from the Session to here
+ // so the surface can be notified of changes from the other UIs.
+ void connect_session_signals();
+
+ // set all controls to their zero position
+ void zero_all();
+
+ /**
+ Fetch the set of routes to be considered for control by the
+ surface. Excluding master, hidden and control routes, and inactive routes
+ */
+ typedef std::vector<boost::shared_ptr<ARDOUR::Route> > Sorted;
+ Sorted get_sorted_routes();
+
+ // bank switching
+ void switch_banks( int initial );
+ void prev_track();
+ void next_track();
+
+ // delete all RouteSignal objects connecting Routes to Strips
+ void clear_route_signals();
+
+ /// This is the main MCU port, ie not an extender port
+ const Mackie::MackiePort & mcu_port() const;
+ Mackie::MackiePort & mcu_port();
+
+ typedef std::vector<Mackie::RouteSignal*> RouteSignals;
+ RouteSignals route_signals;
+
+ // return which of the ports a particular route_table
+ // index belongs to
+ Mackie::MackiePort & port_for_id( uint32_t index );
+
+ /**
+ Handle a button press for the control and return whether
+ the corresponding light should be on or off.
+ */
+ bool handle_strip_button( Mackie::Control &, Mackie::ButtonState, boost::shared_ptr<ARDOUR::Route> );
+
+ /// thread started. Calls monitor_work.
+ static void* _monitor_work (void* arg);
+
+ /// Polling midi port(s) for incoming messages
+ void* monitor_work ();
+
+ /// rebuild the set of ports for this surface
+ void update_ports();
+
+ /// Returns true if there is pending data, false otherwise
+ bool poll_ports();
+
+ /// Trigger the MIDI::Parser
+ void read_ports();
+
+ void add_port( MIDI::Port &, int number );
+
+ /// read automation data from the currently active routes and send to surface
+ void poll_automation();
+
+ // called from poll_automation to figure out which automations need to be sent
+ void update_automation( Mackie::RouteSignal & );
+
+ /**
+ notification that the port is about to start it's init sequence.
+ We must make sure that before this exits, the port is being polled
+ for new data.
+ */
+ void handle_port_init( Mackie::SurfacePort * );
+
+ /// notification from a MackiePort that it's now active
+ void handle_port_active( Mackie::SurfacePort * );
+
+ /// notification from a MackiePort that it's now inactive
+ void handle_port_inactive( Mackie::SurfacePort * );
+
+ boost::shared_ptr<ARDOUR::Route> master_route();
+ Mackie::Strip & master_strip();
+
+ private:
+ boost::shared_ptr<Mackie::RouteSignal> master_route_signal;
+
+ static const char * default_port_name;
+
+ /// The Midi port(s) connected to the units
+ typedef vector<Mackie::MackiePort*> MackiePorts;
+ MackiePorts _ports;
+
+ // the thread that polls the ports for incoming midi data
+ pthread_t thread;
+
+ /// The initial remote_id of the currently switched in bank.
+ uint32_t _current_initial_bank;
+
+ /// protects the port list, and polling structures
+ Glib::Mutex update_mutex;
+
+ /// Protects set_active, and allows waiting on the poll thread
+ Glib::Cond update_cond;
+
+ // because sigc::trackable doesn't seem to be working
+ std::vector<sigc::connection> _connections;
+ std::back_insert_iterator<std::vector<sigc::connection> > connections_back;
+
+ /// The representation of the physical controls on the surface.
+ Mackie::Surface * _surface;
+
+ /// If a port is opened or closed, this will be
+ /// true until the port configuration is updated;
+ bool _ports_changed;
+
+ bool _polling;
+ struct pollfd * pfd;
+ int nfds;
+};
+
+#endif // ardour_mackie_control_protocol_h
diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
new file mode 100644
index 0000000000..05681c0c25
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
@@ -0,0 +1,192 @@
+#include "mackie_control_protocol.h"
+
+#include "midi_byte_array.h"
+#include "surface_port.h"
+
+#include <pbd/pthread_utils.h>
+#include <pbd/error.h>
+
+#include <midi++/types.h>
+#include <midi++/port.h>
+#include <midi++/manager.h>
+#include <midi++/port_request.h>
+#include "i18n.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <errno.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+using namespace std;
+using namespace Mackie;
+using namespace PBD;
+
+const char * MackieControlProtocol::default_port_name = "mcu";
+
+bool MackieControlProtocol::probe()
+{
+ return MIDI::Manager::instance()->port( default_port_name ) != 0;
+}
+
+void * MackieControlProtocol::monitor_work()
+{
+ // What does ThreadCreatedWithRequestSize do?
+ PBD::ThreadCreated (pthread_self(), X_("Mackie"));
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+ // read from midi ports
+ while ( _polling )
+ {
+ try
+ {
+ if ( poll_ports() )
+ {
+ try { read_ports(); }
+ catch ( exception & e ) {
+ cout << "MackieControlProtocol::poll_ports caught exception: " << e.what() << endl;
+ _ports_changed = true;
+ update_ports();
+ }
+ }
+ // poll for automation data from the routes
+ poll_automation();
+ }
+ catch ( exception & e )
+ {
+ cout << "caught exception in MackieControlProtocol::monitor_work " << e.what() << endl;
+ }
+ }
+
+ // TODO ports and pfd and nfds should be in a separate class
+ delete[] pfd;
+ pfd = 0;
+ nfds = 0;
+
+ return (void*) 0;
+}
+
+void MackieControlProtocol::update_ports()
+{
+ if ( _ports_changed )
+ {
+ Glib::Mutex::Lock ul( update_mutex );
+ // yes, this is a double-test locking paradigm, or whatever it's called
+ // because we don't *always* need to acquire the lock for the first test
+ if ( _ports_changed )
+ {
+ // create new pollfd structures
+ if ( pfd != 0 ) delete[] pfd;
+ // TODO This might be a memory leak. How does thread cancellation cleanup work?
+ pfd = new pollfd[_ports.size()];
+ nfds = 0;
+
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ //cout << "adding port " << (*it)->port().name() << " to pollfd" << endl;
+ pfd[nfds].fd = (*it)->port().selectable();
+ pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+ ++nfds;
+ }
+ _ports_changed = false;
+ }
+ update_cond.signal();
+ }
+}
+
+void MackieControlProtocol::read_ports()
+{
+ /* now read any data on the ports */
+ Glib::Mutex::Lock lock( update_mutex );
+ for ( int p = 0; p < nfds; ++p )
+ {
+ // this will cause handle_midi_any in the MackiePort to be triggered
+ if ( pfd[p].revents & POLLIN > 0 )
+ {
+ // avoid deadlocking?
+ // doesn't seem to make a difference
+ //lock.release();
+ _ports[p]->read();
+ //lock.acquire();
+ }
+ }
+}
+
+bool MackieControlProtocol::poll_ports()
+{
+ int timeout = 10; // milliseconds
+ int no_ports_sleep = 1000; // milliseconds
+
+ Glib::Mutex::Lock lock( update_mutex );
+ // if there are no ports
+ if ( nfds < 1 )
+ {
+ lock.release();
+ //cout << "poll_ports no ports" << endl;
+ usleep( no_ports_sleep * 1000 );
+ return false;
+ }
+
+ int retval = poll( pfd, nfds, timeout );
+ if ( retval < 0 )
+ {
+ // gdb at work, perhaps
+ if ( errno != EINTR )
+ {
+ error << string_compose(_("Mackie MIDI thread poll failed (%1)"), strerror( errno ) ) << endmsg;
+ }
+ return false;
+ }
+
+ return retval > 0;
+}
+
+void MackieControlProtocol::handle_port_inactive( SurfacePort * port )
+{
+ // port gone away. So stop polling it ASAP
+ {
+ // delete the port instance
+ Glib::Mutex::Lock lock( update_mutex );
+ MackiePorts::iterator it = find( _ports.begin(), _ports.end(), port );
+ if ( it != _ports.end() )
+ {
+ delete *it;
+ _ports.erase( it );
+ }
+ }
+ _ports_changed = true;
+ update_ports();
+
+ // TODO all the rebuilding of surfaces and so on
+}
+
+void MackieControlProtocol::handle_port_active( SurfacePort * port )
+{
+ // no need to re-add port because it was already added
+ // during the init phase. So just update the local surface
+ // representation and send the representation to
+ // all existing ports
+
+ // TODO update bank size
+
+ // TODO rebuild surface, to have new units
+
+ // finally update session state to the surface
+ // TODO but this is also done in set_active, and
+ // in fact update_surface won't execute unless
+ // _active == true
+ //cout << "update_surface in handle_port_active" << endl;
+ update_surface();
+}
+
+void MackieControlProtocol::handle_port_init( Mackie::SurfacePort * sport )
+{
+ //cout << "MackieControlProtocol::handle_port_init" << endl;
+ _ports_changed = true;
+ update_ports();
+}
diff --git a/libs/surfaces/mackie/mackie_midi_builder.cc b/libs/surfaces/mackie/mackie_midi_builder.cc
new file mode 100644
index 0000000000..8ed98a5720
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_midi_builder.cc
@@ -0,0 +1,173 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 "mackie_midi_builder.h"
+
+#include <typeinfo>
+#include <sstream>
+#include <iomanip>
+
+#include "controls.h"
+#include "midi_byte_array.h"
+
+using namespace Mackie;
+using namespace std;
+
+MIDI::byte MackieMidiBuilder::calculate_pot_value( midi_pot_mode mode, const ControlState & state )
+{
+ // TODO do an exact calc for 0.50? To allow manually re-centering the port.
+
+ // center on or off
+ MIDI::byte retval = ( state.pos > 0.45 && state.pos < 0.55 ? 1 : 0 ) << 6;
+
+ // mode
+ retval |= ( mode << 4 );
+
+ // value, but only if off hasn't explicitly been set
+ if ( state.led_state != off )
+ retval += ( int(state.pos * 10.0) + 1 ) & 0x0f; // 0b00001111
+
+ return retval;
+}
+
+MidiByteArray MackieMidiBuilder::build_led_ring( const Pot & pot, const ControlState & state )
+{
+ return build_led_ring( pot.led_ring(), state );
+}
+
+MidiByteArray MackieMidiBuilder::build_led_ring( const LedRing & led_ring, const ControlState & state )
+{
+ // The other way of doing this:
+ // 0x30 + pot/ring number (0-7)
+ //, 0x30 + led_ring.ordinal() - 1
+ return MidiByteArray ( 3
+ // the control type
+ , midi_pot_id
+ // the id
+ , 0x20 + led_ring.id()
+ // the value
+ , calculate_pot_value( midi_pot_mode_dot, state )
+ );
+}
+
+MidiByteArray MackieMidiBuilder::build_led( const Button & button, LedState ls )
+{
+ return build_led( button.led(), ls );
+}
+
+MidiByteArray MackieMidiBuilder::build_led( const Led & led, LedState ls )
+{
+ MIDI::byte state = 0;
+ switch ( ls.state() )
+ {
+ case LedState::on: state = 0x7f; break;
+ case LedState::off: state = 0x00; break;
+ case LedState::none: state = 0x00; break; // actually, this should never happen.
+ case LedState::flashing: state = 0x01; break;
+ }
+
+ return MidiByteArray ( 3
+ , midi_button_id
+ , led.id()
+ , state
+ );
+}
+
+MidiByteArray MackieMidiBuilder::build_fader( const Fader & fader, float pos )
+{
+ int posi = int( 0x3fff * pos );
+
+ return MidiByteArray ( 3
+ , midi_fader_id | fader.id()
+ // lower-order bits
+ , posi & 0x7f
+ // higher-order bits
+ , ( posi >> 7 )
+ );
+}
+
+MidiByteArray MackieMidiBuilder::zero_strip( const Strip & strip )
+{
+ Group::Controls::const_iterator it = strip.controls().begin();
+ MidiByteArray retval;
+ for (; it != strip.controls().end(); ++it )
+ {
+ Control & control = **it;
+ if ( control.accepts_feedback() )
+ retval << zero_control( control );
+ }
+ return retval;
+}
+
+MidiByteArray MackieMidiBuilder::zero_control( const Control & control )
+{
+ switch( control.type() )
+ {
+ case Control::type_button:
+ return build_led( (Button&)control, off );
+
+ case Control::type_led:
+ return build_led( (Led&)control, off );
+
+ case Control::type_fader:
+ return build_fader( (Fader&)control, 0.0 );
+
+ case Control::type_pot:
+ return build_led_ring( dynamic_cast<const Pot&>( control ), off );
+
+ case Control::type_led_ring:
+ return build_led_ring( dynamic_cast<const LedRing&>( control ), off );
+
+ default:
+ ostringstream os;
+ os << "Unknown control type " << control << " in Strip::zero_control";
+ throw MackieControlException( os.str() );
+ }
+}
+
+char translate_seven_segment( char achar )
+{
+ achar = toupper( achar );
+ if ( achar >= 0x40 && achar <= 0x60 )
+ return achar - 0x40;
+ else if ( achar >= 0x21 && achar <= 0x3f )
+ return achar;
+ else
+ return 0x00;
+}
+
+MidiByteArray MackieMidiBuilder::two_char_display( const std::string & msg, const std::string & dots )
+{
+ if ( msg.length() != 2 ) throw MackieControlException( "MackieMidiBuilder::two_char_display: msg must be exactly 2 characters" );
+ if ( dots.length() != 2 ) throw MackieControlException( "MackieMidiBuilder::two_char_display: dots must be exactly 2 characters" );
+
+ MidiByteArray bytes( 5, 0xb0, 0x4a, 0x00, 0x4b, 0x00 );
+
+ // chars are understood by the surface in right-to-left order
+ // could also exchange the 0x4a and 0x4b, above
+ bytes[4] = translate_seven_segment( msg[0] ) + ( dots[0] == '.' ? 0x40 : 0x00 );
+ bytes[2] = translate_seven_segment( msg[1] ) + ( dots[1] == '.' ? 0x40 : 0x00 );
+
+ return bytes;
+}
+
+MidiByteArray MackieMidiBuilder::two_char_display( unsigned int value, const std::string & dots )
+{
+ ostringstream os;
+ os << setfill('0') << setw(2) << value % 100;
+ return two_char_display( os.str() );
+}
diff --git a/libs/surfaces/mackie/mackie_midi_builder.h b/libs/surfaces/mackie/mackie_midi_builder.h
new file mode 100644
index 0000000000..f0c3d51a54
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_midi_builder.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 mackie_midi_builder_h
+#define mackie_midi_builder_h
+
+#include "midi_byte_array.h"
+#include "types.h"
+
+namespace Mackie
+{
+
+/**
+ This knows how to build midi messages given a control and
+ a state.
+*/
+class MackieMidiBuilder
+{
+public:
+ /**
+ The first byte of a midi message from the surface
+ will contain one of these, sometimes bitmasked
+ with the control id
+ */
+ enum midi_types {
+ midi_fader_id = 0xe0
+ , midi_button_id = 0x90
+ , midi_pot_id = 0xb0
+ };
+
+ /**
+ The LED rings have these modes.
+ */
+ enum midi_pot_mode {
+ midi_pot_mode_dot = 0
+ , midi_pot_mode_boost_cut = 1
+ , midi_pot_mode_wrap = 2
+ , midi_pot_mode_spread = 3
+ };
+
+ MidiByteArray build_led_ring( const Pot & pot, const ControlState & );
+ MidiByteArray build_led_ring( const LedRing & led_ring, const ControlState & );
+
+ MidiByteArray build_led( const Led & led, LedState ls );
+ MidiByteArray build_led( const Button & button, LedState ls );
+
+ MidiByteArray build_fader( const Fader & fader, float pos );
+
+ /// return bytes that will reset all controls to their zero positions
+ MidiByteArray zero_strip( const Strip & strip );
+
+ // provide bytes to zero the given control
+ MidiByteArray zero_control( const Control & control );
+
+ // display the first 2 chars of the msg in the 2 char display
+ // . is appended to the previous character, so A.B. would
+ // be two characters
+ MidiByteArray two_char_display( const std::string & msg, const std::string & dots = " " );
+ MidiByteArray two_char_display( unsigned int value, const std::string & dots = " " );
+
+protected:
+ static MIDI::byte calculate_pot_value( midi_pot_mode mode, const ControlState & );
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_port.cc b/libs/surfaces/mackie/mackie_port.cc
new file mode 100644
index 0000000000..9bcee638fb
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_port.cc
@@ -0,0 +1,399 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 "mackie_port.h"
+
+#include "mackie_control_exception.h"
+#include "mackie_control_protocol.h"
+#include "mackie_midi_builder.h"
+#include "controls.h"
+#include "surface.h"
+
+#include <midi++/types.h>
+#include <midi++/port.h>
+#include <sigc++/sigc++.h>
+#include <boost/shared_array.hpp>
+#include <ardour/configuration.h>
+
+#include "i18n.h"
+
+#include <sstream>
+
+using namespace std;
+using namespace Mackie;
+
+// The MCU sysex header
+MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 );
+
+// The MCU extender sysex header
+MidiByteArray mackie_sysex_hdr_xt ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11 );
+
+MackiePort::MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int number, port_type_t port_type )
+: SurfacePort( port, number )
+, _mcp( mcp )
+, _port_type( port_type )
+, _emulation( none )
+, _initialising( true )
+{
+ //cout << "MackiePort::MackiePort" <<endl;
+}
+
+MackiePort::~MackiePort()
+{
+ //cout << "~MackiePort" << endl;
+ close();
+ //cout << "~MackiePort finished" << endl;
+}
+
+int MackiePort::strips() const
+{
+ if ( _port_type == mcu )
+ {
+ switch ( _emulation )
+ {
+ // BCF2000 only has 8 faders, so reserve one for master
+ case bcf2000: return 7;
+ case mackie: return 8;
+ case none:
+ default:
+ throw MackieControlException( "MackiePort::strips: don't know what emulation we're using" );
+ }
+ }
+ else
+ {
+ // must be an extender, ie no master fader
+ return 8;
+ }
+}
+
+// should really be in MackiePort
+void MackiePort::open()
+{
+ //cout << "MackiePort::open " << *this << endl;
+ _sysex = port().input()->sysex.connect( ( mem_fun (*this, &MackiePort::handle_midi_sysex) ) );
+
+ // make sure the device is connected
+ init();
+}
+
+void MackiePort::close()
+{
+ //cout << "MackiePort::close" << endl;
+
+ // disconnect signals
+ _any.disconnect();
+ _sysex.disconnect();
+
+ // TODO emit a "closing" signal?
+ //cout << "MackiePort::close finished" << endl;
+}
+
+const MidiByteArray & MackiePort::sysex_hdr() const
+{
+ switch ( _port_type )
+ {
+ case mcu: return mackie_sysex_hdr;
+ case ext: return mackie_sysex_hdr_xt;
+ }
+ cout << "MackiePort::sysex_hdr _port_type not known" << endl;
+ return mackie_sysex_hdr;
+}
+
+Control & MackiePort::lookup_control( const MidiByteArray & bytes )
+{
+ Control * control = 0;
+ int midi_id = -1;
+ MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
+ switch( midi_type )
+ {
+ // fader
+ case MackieMidiBuilder::midi_fader_id:
+ midi_id = bytes[0] & 0x0f;
+ control = _mcp.surface().faders[midi_id];
+ if ( control == 0 )
+ {
+ ostringstream os;
+ os << "control for fader" << midi_id << " is null";
+ throw MackieControlException( os.str() );
+ }
+ break;
+
+ // button
+ case MackieMidiBuilder::midi_button_id:
+ midi_id = bytes[1];
+ control = _mcp.surface().buttons[midi_id];
+ if ( control == 0 )
+ {
+ ostringstream os;
+ os << "control for button" << midi_id << " is null";
+ throw MackieControlException( os.str() );
+ }
+ break;
+
+ // pot (jog wheel, external control)
+ case MackieMidiBuilder::midi_pot_id:
+ midi_id = bytes[1] & 0x1f;
+ control = _mcp.surface().pots[midi_id];
+ if ( control == 0 )
+ {
+ ostringstream os;
+ os << "control for button" << midi_id << " is null";
+ throw MackieControlException( os.str() );
+ }
+ break;
+
+ default:
+ ostringstream os;
+ os << "Cannot find control for " << bytes;
+ throw MackieControlException( os.str() );
+ }
+ return *control;
+}
+
+MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiByteArray::iterator end )
+{
+ MidiByteArray l;
+ back_insert_iterator<MidiByteArray> back ( l );
+ copy( begin, end, back );
+
+ MidiByteArray retval;
+
+ // this is how to calculate the response to the challenge.
+ // from the Logic docs.
+ retval << ( 0x7f & ( l[0] + ( l[1] ^ 0xa ) - l[3] ) );
+ retval << ( 0x7f & ( ( l[2] >> l[3] ) ^ ( l[0] + l[3] ) ) );
+ retval << ( 0x7f & ( l[3] - ( l[2] << 2 ) ^ ( l[0] | l[1] ) ) );
+ retval << ( 0x7f & ( l[1] - l[2] + ( 0xf0 ^ ( l[3] << 4 ) ) ) );
+
+ return retval;
+}
+
+// not used right now
+MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes )
+{
+ // handle host connection query
+ //cout << "host connection query: " << bytes << endl;
+
+ if ( bytes.size() != 18 )
+ {
+ finalise_init( false );
+ ostringstream os;
+ os << "expecting 18 bytes, read " << bytes << " from " << port().name();
+ throw MackieControlException( os.str() );
+ }
+
+ // build and send host connection reply
+ MidiByteArray response;
+ response << 0x02;
+ copy( bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter( response ) );
+ response << calculate_challenge_response( bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4 );
+ return response;
+}
+
+// not used right now
+MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes )
+{
+ //cout << "host_connection_confirmation: " << bytes << endl;
+
+ // decode host connection confirmation
+ if ( bytes.size() != 14 )
+ {
+ finalise_init( false );
+ ostringstream os;
+ os << "expecting 14 bytes, read " << bytes << " from " << port().name();
+ throw MackieControlException( os.str() );
+ }
+
+ // send version request
+ return MidiByteArray( 2, 0x13, 0x00 );
+}
+
+void MackiePort::probe_emulation( const MidiByteArray & bytes )
+{
+ //cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
+ string version_string;
+ for ( int i = 6; i < 11; ++i ) version_string.append( 1, (char)bytes[i] );
+ //cout << "version_string: " << version_string << endl;
+
+ // TODO investigate using serial number. Also, possibly size of bytes might
+ // give an indication. Also, apparently MCU sends non-documented messages
+ // sometimes.
+ if (!_initialising)
+ {
+ cout << "MackiePort::probe_emulation out of sequence." << endl;
+ return;
+ }
+
+ finalise_init( true );
+}
+
+void MackiePort::init()
+{
+ //cout << "MackiePort::init" << endl;
+ init_mutex.lock();
+ _initialising = true;
+
+ //cout << "MackiePort::lock acquired" << endl;
+ // emit pre-init signal
+ init_event();
+
+ // kick off initialisation. See docs in header file for init()
+
+ // bypass the init sequence because sometimes the first
+ // message doesn't get to the unit, and there's no way
+ // to do a timed lock in Glib.
+ //write_sysex ( MidiByteArray ( 2, 0x13, 0x00 ) );
+
+ finalise_init( true );
+}
+
+void MackiePort::finalise_init( bool yn )
+{
+ //cout << "MackiePort::finalise_init" << endl;
+ bool emulation_ok = false;
+
+ // probing doesn't work very well, so just use a config variable
+ // to set the emulation mode
+ if ( _emulation == none )
+ {
+ if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
+ {
+ _emulation = bcf2000;
+ emulation_ok = true;
+ }
+ else if ( ARDOUR::Config->get_mackie_emulation() == "mcu" )
+ {
+ _emulation = mackie;
+ emulation_ok = true;
+ }
+ else
+ {
+ cout << "unknown mackie emulation: " << ARDOUR::Config->get_mackie_emulation() << endl;
+ emulation_ok = false;
+ }
+ }
+
+ yn = yn && emulation_ok;
+
+ SurfacePort::active( yn );
+
+ if ( yn )
+ {
+ active_event();
+
+ // start handling messages from controls
+ _any = port().input()->any.connect( ( mem_fun (*this, &MackiePort::handle_midi_any) ) );
+ }
+ _initialising = false;
+ init_cond.signal();
+ init_mutex.unlock();
+}
+
+bool MackiePort::wait_for_init()
+{
+ Glib::Mutex::Lock lock( init_mutex );
+ while ( _initialising )
+ {
+ //cout << "MackiePort::wait_for_active waiting" << endl;
+ init_cond.wait( init_mutex );
+ //cout << "MackiePort::wait_for_active released" << endl;
+ }
+ //cout << "MackiePort::wait_for_active returning" << endl;
+ return SurfacePort::active();
+}
+
+void MackiePort::handle_midi_sysex (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
+{
+ MidiByteArray bytes( count, raw_bytes );
+ //cout << "handle_midi_sysex: " << bytes << endl;
+ switch( bytes[5] )
+ {
+ case 0x01:
+ // not used right now
+ write_sysex( host_connection_query( bytes ) );
+ break;
+ case 0x03:
+ // not used right now
+ write_sysex( host_connection_confirmation( bytes ) );
+ break;
+ case 0x04:
+ inactive_event();
+ cout << "host connection error" << bytes << endl;
+ break;
+ case 0x14:
+ probe_emulation( bytes );
+ break;
+ default:
+ cout << "unknown sysex: " << bytes << endl;
+ }
+}
+
+// converts midi messages into control_event signals
+void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
+{
+ MidiByteArray bytes( count, raw_bytes );
+ try
+ {
+ // ignore sysex messages
+ if ( bytes[0] == MIDI::sysex ) return;
+
+ Control & control = lookup_control( bytes );
+
+ // This handles incoming bytes. Outgoing bytes
+ // are sent by the signal handlers.
+ switch ( control.type() )
+ {
+ // fader
+ case Control::type_fader:
+ {
+ // for a BCF2000, max is 7f for high-order byte and 0x70 for low-order byte
+ // According to the Logic docs, these should both be 0x7f.
+ // Although it does mention something about only the top-order
+ // 10 bits out of 14 being used
+ int midi_pos = ( bytes[2] << 7 ) + bytes[1];
+ control_event( *this, control, float(midi_pos) / float(0x3fff) );
+ }
+ break;
+
+ // button
+ case Control::type_button:
+ control_event( *this, control, bytes[2] == 0x7f ? press : release );
+ break;
+
+ // pot (jog wheel, external control)
+ case Control::type_pot:
+ {
+ ControlState state;
+
+ // bytes[2] & 0b01000000 (0x40) give sign
+ int sign = ( bytes[2] & 0x40 ) == 0 ? 1 : -1;
+ // bytes[2] & 0b00111111 (0x3f) gives delta
+ state.ticks = ( bytes[2] & 0x3f) * sign;
+ state.delta = float( state.ticks ) / float( 0x3f );
+
+ control_event( *this, control, state );
+ }
+ break;
+ default:
+ cerr << "Do not understand control type " << control;
+ }
+ }
+ catch( MackieControlException & e )
+ {
+ //cout << bytes << ' ' << e.what() << endl;
+ }
+}
diff --git a/libs/surfaces/mackie/mackie_port.h b/libs/surfaces/mackie/mackie_port.h
new file mode 100644
index 0000000000..2ad5cf6154
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_port.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 mackie_port_h
+#define mackie_port_h
+
+#include "surface_port.h"
+
+#include <midi++/types.h>
+#include <sigc++/signal.h>
+#include <sigc++/connection.h>
+
+#include <glibmm/thread.h>
+
+#include "midi_byte_array.h"
+#include "types.h"
+
+namespace MIDI {
+ class Port;
+ class Parser;
+}
+
+class MackieControlProtocol;
+
+namespace Mackie
+{
+
+class MackiePort : public SurfacePort
+{
+public:
+ enum port_type_t { mcu, ext };
+ enum emulation_t { none, mackie, bcf2000 };
+
+ MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int number, port_type_t = mcu );
+ ~MackiePort();
+
+ virtual void open();
+ virtual void close();
+
+ /// MCU and extenders have different sysex headers
+ virtual const MidiByteArray & sysex_hdr() const;
+
+ /// Handle device initialisation
+ void handle_midi_sysex( MIDI::Parser &, MIDI::byte *, size_t );
+
+ /// Handle all control messags
+ void handle_midi_any( MIDI::Parser &, MIDI::byte *, size_t );
+
+ Control & lookup_control( const MidiByteArray & bytes );
+
+ /// return the number of strips associated with this port
+ virtual int strips() const;
+
+ /// Block until the port has finished initialising, and then return
+ /// whether the intialisation succeeded
+ bool wait_for_init();
+
+ emulation_t emulation() const { return _emulation; }
+
+protected:
+ /**
+ The initialisation sequence is fairly complex. First a lock is acquired
+ so that a condition can be used to signal the end of the init process.
+ Then a sysex is sent to the device. The response to the sysex
+ is handled by a switch in handle_midi_sysex which calls one of the
+ other methods.
+
+ However, windows DAWs ignore the documented init sequence and so we
+ do too. Thanks to Essox for helping with this.
+
+ So we use the version firmware to figure out what device is on
+ the other end of the cable.
+ */
+ void init();
+
+ /**
+ Once the device is initialised, finalise_init(true) is called, which
+ releases the lock and signals the condition, and starts handling incoming
+ messages. finalise_init(false) will also release the lock but doesn't
+ start handling messages.
+ */
+ void finalise_init( bool yn );
+
+ MidiByteArray host_connection_query( MidiByteArray & bytes );
+ MidiByteArray host_connection_confirmation( const MidiByteArray & bytes );
+
+ /**
+ Will set _emulation to what it thinks is correct, based
+ on responses from the device. Or get/set parameters. Or
+ environment variables. Or existence of a file.
+ */
+ void probe_emulation( const MidiByteArray & bytes );
+
+private:
+ MackieControlProtocol & _mcp;
+ port_type_t _port_type;
+ sigc::connection _any;
+ sigc::connection _sysex;
+ emulation_t _emulation;
+
+ bool _initialising;
+ Glib::Cond init_cond;
+ Glib::Mutex init_mutex;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_surface.cc b/libs/surfaces/mackie/mackie_surface.cc
new file mode 100644
index 0000000000..b527f710cc
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_surface.cc
@@ -0,0 +1,1504 @@
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "mackie_surface.h"
+
+#include "controls.h"
+#include "mackie_button_handler.h"
+
+using namespace Mackie;
+
+void Mackie::MackieSurface::init_controls()
+{
+ // intialise groups and strips
+ Group * group = 0;
+
+ // make sure there are enough strips
+ strips.resize( 8 );
+
+ group = new Group ( "user" );
+ groups["user"] = group;
+
+ group = new Group ( "assignment" );
+ groups["assignment"] = group;
+
+ group = new Group ( "none" );
+ groups["none"] = group;
+
+ group = new MasterStrip ( "master", 0 );
+ groups["master"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_1", 0 );
+ groups["strip_1"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "cursor" );
+ groups["cursor"] = group;
+
+ group = new Strip ( "strip_2", 1 );
+ groups["strip_2"] = group;
+ strips[1] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "functions" );
+ groups["functions"] = group;
+
+ group = new Group ( "automation" );
+ groups["automation"] = group;
+
+ group = new Strip ( "strip_3", 2 );
+ groups["strip_3"] = group;
+ strips[2] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "display" );
+ groups["display"] = group;
+
+ group = new Strip ( "strip_4", 3 );
+ groups["strip_4"] = group;
+ strips[3] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_5", 4 );
+ groups["strip_5"] = group;
+ strips[4] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_6", 5 );
+ groups["strip_6"] = group;
+ strips[5] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "transport" );
+ groups["transport"] = group;
+
+ group = new Strip ( "strip_7", 6 );
+ groups["strip_7"] = group;
+ strips[6] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "modifiers" );
+ groups["modifiers"] = group;
+
+ group = new Group ( "bank" );
+ groups["bank"] = group;
+
+ group = new Strip ( "strip_8", 7 );
+ groups["strip_8"] = group;
+ strips[7] = dynamic_cast<Strip*>( group );
+
+
+ // initialise controls
+ Control * control = 0;
+
+ group = groups["strip_1"];
+ control = new Fader ( 0, 1, "gain", *group );
+ faders[0x00] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Fader ( 1, 2, "gain", *group );
+ faders[0x01] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Fader ( 2, 3, "gain", *group );
+ faders[0x02] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Fader ( 3, 4, "gain", *group );
+ faders[0x03] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Fader ( 4, 5, "gain", *group );
+ faders[0x04] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Fader ( 5, 6, "gain", *group );
+ faders[0x05] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Fader ( 6, 7, "gain", *group );
+ faders[0x06] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Fader ( 7, 8, "gain", *group );
+ faders[0x07] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["master"];
+ control = new Fader ( 8, 1, "gain", *group );
+ faders[0x08] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Pot ( 16, 1, "vpot", *group );
+ pots[0x10] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Pot ( 17, 2, "vpot", *group );
+ pots[0x11] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Pot ( 18, 3, "vpot", *group );
+ pots[0x12] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Pot ( 19, 4, "vpot", *group );
+ pots[0x13] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Pot ( 20, 5, "vpot", *group );
+ pots[0x14] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Pot ( 21, 6, "vpot", *group );
+ pots[0x15] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Pot ( 22, 7, "vpot", *group );
+ pots[0x16] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Pot ( 23, 8, "vpot", *group );
+ pots[0x17] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Pot ( 60, 1, "jog", *group );
+ pots[0x3c] = control;
+ controls.push_back( control );
+ controls_by_name["jog"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Pot ( 46, 1, "external", *group );
+ pots[0x2e] = control;
+ controls.push_back( control );
+ controls_by_name["external"] = control;
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 0, 1, "recenable", *group );
+ buttons[0x00] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 1, 2, "recenable", *group );
+ buttons[0x01] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 2, 3, "recenable", *group );
+ buttons[0x02] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 3, 4, "recenable", *group );
+ buttons[0x03] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 4, 5, "recenable", *group );
+ buttons[0x04] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 5, 6, "recenable", *group );
+ buttons[0x05] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 6, 7, "recenable", *group );
+ buttons[0x06] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Button ( 7, 8, "recenable", *group );
+ buttons[0x07] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 8, 1, "solo", *group );
+ buttons[0x08] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 9, 2, "solo", *group );
+ buttons[0x09] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 10, 3, "solo", *group );
+ buttons[0x0a] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 11, 4, "solo", *group );
+ buttons[0x0b] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 12, 5, "solo", *group );
+ buttons[0x0c] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 13, 6, "solo", *group );
+ buttons[0x0d] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 14, 7, "solo", *group );
+ buttons[0x0e] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Button ( 15, 8, "solo", *group );
+ buttons[0x0f] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 16, 1, "mute", *group );
+ buttons[0x10] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 17, 2, "mute", *group );
+ buttons[0x11] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 18, 3, "mute", *group );
+ buttons[0x12] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 19, 4, "mute", *group );
+ buttons[0x13] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 20, 5, "mute", *group );
+ buttons[0x14] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 21, 6, "mute", *group );
+ buttons[0x15] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 22, 7, "mute", *group );
+ buttons[0x16] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Button ( 23, 8, "mute", *group );
+ buttons[0x17] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 24, 1, "select", *group );
+ buttons[0x18] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 25, 2, "select", *group );
+ buttons[0x19] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 26, 3, "select", *group );
+ buttons[0x1a] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 27, 4, "select", *group );
+ buttons[0x1b] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 28, 5, "select", *group );
+ buttons[0x1c] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 29, 6, "select", *group );
+ buttons[0x1d] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 30, 7, "select", *group );
+ buttons[0x1e] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Button ( 31, 8, "select", *group );
+ buttons[0x1f] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 32, 1, "vselect", *group );
+ buttons[0x20] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 33, 2, "vselect", *group );
+ buttons[0x21] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 34, 3, "vselect", *group );
+ buttons[0x22] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 35, 4, "vselect", *group );
+ buttons[0x23] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 36, 5, "vselect", *group );
+ buttons[0x24] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 37, 6, "vselect", *group );
+ buttons[0x25] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 38, 7, "vselect", *group );
+ buttons[0x26] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Button ( 39, 8, "vselect", *group );
+ buttons[0x27] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 40, 1, "io", *group );
+ buttons[0x28] = control;
+ controls.push_back( control );
+ controls_by_name["io"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 41, 1, "sends", *group );
+ buttons[0x29] = control;
+ controls.push_back( control );
+ controls_by_name["sends"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 42, 1, "pan", *group );
+ buttons[0x2a] = control;
+ controls.push_back( control );
+ controls_by_name["pan"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 43, 1, "plugin", *group );
+ buttons[0x2b] = control;
+ controls.push_back( control );
+ controls_by_name["plugin"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 44, 1, "eq", *group );
+ buttons[0x2c] = control;
+ controls.push_back( control );
+ controls_by_name["eq"] = control;
+ group->add( *control );
+
+ group = groups["assignment"];
+ control = new Button ( 45, 1, "dyn", *group );
+ buttons[0x2d] = control;
+ controls.push_back( control );
+ controls_by_name["dyn"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 46, 1, "left", *group );
+ buttons[0x2e] = control;
+ controls.push_back( control );
+ controls_by_name["left"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 47, 1, "right", *group );
+ buttons[0x2f] = control;
+ controls.push_back( control );
+ controls_by_name["right"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 48, 1, "channel_left", *group );
+ buttons[0x30] = control;
+ controls.push_back( control );
+ controls_by_name["channel_left"] = control;
+ group->add( *control );
+
+ group = groups["bank"];
+ control = new Button ( 49, 1, "channel_right", *group );
+ buttons[0x31] = control;
+ controls.push_back( control );
+ controls_by_name["channel_right"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 50, 1, "flip", *group );
+ buttons[0x32] = control;
+ controls.push_back( control );
+ controls_by_name["flip"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 51, 1, "edit", *group );
+ buttons[0x33] = control;
+ controls.push_back( control );
+ controls_by_name["edit"] = control;
+ group->add( *control );
+
+ group = groups["display"];
+ control = new Button ( 52, 1, "name_value", *group );
+ buttons[0x34] = control;
+ controls.push_back( control );
+ controls_by_name["name_value"] = control;
+ group->add( *control );
+
+ group = groups["display"];
+ control = new Button ( 53, 1, "smpte_beats", *group );
+ buttons[0x35] = control;
+ controls.push_back( control );
+ controls_by_name["smpte_beats"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 54, 1, "F1", *group );
+ buttons[0x36] = control;
+ controls.push_back( control );
+ controls_by_name["F1"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 55, 1, "F2", *group );
+ buttons[0x37] = control;
+ controls.push_back( control );
+ controls_by_name["F2"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 56, 1, "F3", *group );
+ buttons[0x38] = control;
+ controls.push_back( control );
+ controls_by_name["F3"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 57, 1, "F4", *group );
+ buttons[0x39] = control;
+ controls.push_back( control );
+ controls_by_name["F4"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 58, 1, "F5", *group );
+ buttons[0x3a] = control;
+ controls.push_back( control );
+ controls_by_name["F5"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 59, 1, "F6", *group );
+ buttons[0x3b] = control;
+ controls.push_back( control );
+ controls_by_name["F6"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 60, 1, "F7", *group );
+ buttons[0x3c] = control;
+ controls.push_back( control );
+ controls_by_name["F7"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 61, 1, "F8", *group );
+ buttons[0x3d] = control;
+ controls.push_back( control );
+ controls_by_name["F8"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 62, 1, "F9", *group );
+ buttons[0x3e] = control;
+ controls.push_back( control );
+ controls_by_name["F9"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 63, 1, "F10", *group );
+ buttons[0x3f] = control;
+ controls.push_back( control );
+ controls_by_name["F10"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 64, 1, "F11", *group );
+ buttons[0x40] = control;
+ controls.push_back( control );
+ controls_by_name["F11"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 65, 1, "F12", *group );
+ buttons[0x41] = control;
+ controls.push_back( control );
+ controls_by_name["F12"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 66, 1, "F13", *group );
+ buttons[0x42] = control;
+ controls.push_back( control );
+ controls_by_name["F13"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 67, 1, "F14", *group );
+ buttons[0x43] = control;
+ controls.push_back( control );
+ controls_by_name["F14"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 68, 1, "F15", *group );
+ buttons[0x44] = control;
+ controls.push_back( control );
+ controls_by_name["F15"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 69, 1, "F16", *group );
+ buttons[0x45] = control;
+ controls.push_back( control );
+ controls_by_name["F16"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 70, 1, "shift", *group );
+ buttons[0x46] = control;
+ controls.push_back( control );
+ controls_by_name["shift"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 71, 1, "option", *group );
+ buttons[0x47] = control;
+ controls.push_back( control );
+ controls_by_name["option"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 72, 1, "control", *group );
+ buttons[0x48] = control;
+ controls.push_back( control );
+ controls_by_name["control"] = control;
+ group->add( *control );
+
+ group = groups["modifiers"];
+ control = new Button ( 73, 1, "cmd_alt", *group );
+ buttons[0x49] = control;
+ controls.push_back( control );
+ controls_by_name["cmd_alt"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 74, 1, "on", *group );
+ buttons[0x4a] = control;
+ controls.push_back( control );
+ controls_by_name["on"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 75, 1, "rec_ready", *group );
+ buttons[0x4b] = control;
+ controls.push_back( control );
+ controls_by_name["rec_ready"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 76, 1, "undo", *group );
+ buttons[0x4c] = control;
+ controls.push_back( control );
+ controls_by_name["undo"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 77, 1, "snapshot", *group );
+ buttons[0x4d] = control;
+ controls.push_back( control );
+ controls_by_name["snapshot"] = control;
+ group->add( *control );
+
+ group = groups["automation"];
+ control = new Button ( 78, 1, "touch", *group );
+ buttons[0x4e] = control;
+ controls.push_back( control );
+ controls_by_name["touch"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 79, 1, "redo", *group );
+ buttons[0x4f] = control;
+ controls.push_back( control );
+ controls_by_name["redo"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 80, 1, "marker", *group );
+ buttons[0x50] = control;
+ controls.push_back( control );
+ controls_by_name["marker"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 81, 1, "enter", *group );
+ buttons[0x51] = control;
+ controls.push_back( control );
+ controls_by_name["enter"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 82, 1, "cancel", *group );
+ buttons[0x52] = control;
+ controls.push_back( control );
+ controls_by_name["cancel"] = control;
+ group->add( *control );
+
+ group = groups["functions"];
+ control = new Button ( 83, 1, "mixer", *group );
+ buttons[0x53] = control;
+ controls.push_back( control );
+ controls_by_name["mixer"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 84, 1, "frm_left", *group );
+ buttons[0x54] = control;
+ controls.push_back( control );
+ controls_by_name["frm_left"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 85, 1, "frm_right", *group );
+ buttons[0x55] = control;
+ controls.push_back( control );
+ controls_by_name["frm_right"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 86, 1, "loop", *group );
+ buttons[0x56] = control;
+ controls.push_back( control );
+ controls_by_name["loop"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 87, 1, "punch_in", *group );
+ buttons[0x57] = control;
+ controls.push_back( control );
+ controls_by_name["punch_in"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 88, 1, "punch_out", *group );
+ buttons[0x58] = control;
+ controls.push_back( control );
+ controls_by_name["punch_out"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 89, 1, "home", *group );
+ buttons[0x59] = control;
+ controls.push_back( control );
+ controls_by_name["home"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 90, 1, "end", *group );
+ buttons[0x5a] = control;
+ controls.push_back( control );
+ controls_by_name["end"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 91, 1, "rewind", *group );
+ buttons[0x5b] = control;
+ controls.push_back( control );
+ controls_by_name["rewind"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 92, 1, "ffwd", *group );
+ buttons[0x5c] = control;
+ controls.push_back( control );
+ controls_by_name["ffwd"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 93, 1, "stop", *group );
+ buttons[0x5d] = control;
+ controls.push_back( control );
+ controls_by_name["stop"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 94, 1, "play", *group );
+ buttons[0x5e] = control;
+ controls.push_back( control );
+ controls_by_name["play"] = control;
+ group->add( *control );
+
+ group = groups["transport"];
+ control = new Button ( 95, 1, "record", *group );
+ buttons[0x5f] = control;
+ controls.push_back( control );
+ controls_by_name["record"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 96, 1, "cursor_up", *group );
+ buttons[0x60] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_up"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 97, 1, "cursor_down", *group );
+ buttons[0x61] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_down"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 98, 1, "cursor_left", *group );
+ buttons[0x62] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_left"] = control;
+ group->add( *control );
+
+ group = groups["cursor"];
+ control = new Button ( 99, 1, "cursor_right", *group );
+ buttons[0x63] = control;
+ controls.push_back( control );
+ controls_by_name["cursor_right"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 100, 1, "zoom", *group );
+ buttons[0x64] = control;
+ controls.push_back( control );
+ controls_by_name["zoom"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Button ( 101, 1, "scrub", *group );
+ buttons[0x65] = control;
+ controls.push_back( control );
+ controls_by_name["scrub"] = control;
+ group->add( *control );
+
+ group = groups["user"];
+ control = new Button ( 102, 1, "user_a", *group );
+ buttons[0x66] = control;
+ controls.push_back( control );
+ controls_by_name["user_a"] = control;
+ group->add( *control );
+
+ group = groups["user"];
+ control = new Button ( 103, 1, "user_b", *group );
+ buttons[0x67] = control;
+ controls.push_back( control );
+ controls_by_name["user_b"] = control;
+ group->add( *control );
+
+ group = groups["strip_1"];
+ control = new Button ( 104, 1, "fader_touch", *group );
+ buttons[0x68] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_2"];
+ control = new Button ( 105, 2, "fader_touch", *group );
+ buttons[0x69] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_3"];
+ control = new Button ( 106, 3, "fader_touch", *group );
+ buttons[0x6a] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_4"];
+ control = new Button ( 107, 4, "fader_touch", *group );
+ buttons[0x6b] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_5"];
+ control = new Button ( 108, 5, "fader_touch", *group );
+ buttons[0x6c] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_6"];
+ control = new Button ( 109, 6, "fader_touch", *group );
+ buttons[0x6d] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_7"];
+ control = new Button ( 110, 7, "fader_touch", *group );
+ buttons[0x6e] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["strip_8"];
+ control = new Button ( 111, 8, "fader_touch", *group );
+ buttons[0x6f] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["master"];
+ control = new Button ( 112, 1, "fader_touch", *group );
+ buttons[0x70] = control;
+ controls.push_back( control );
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 113, 1, "smpte", *group );
+ leds[0x71] = control;
+ controls.push_back( control );
+ controls_by_name["smpte"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 114, 1, "beats", *group );
+ leds[0x72] = control;
+ controls.push_back( control );
+ controls_by_name["beats"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 115, 1, "solo", *group );
+ leds[0x73] = control;
+ controls.push_back( control );
+ controls_by_name["solo"] = control;
+ group->add( *control );
+
+ group = groups["none"];
+ control = new Led ( 118, 1, "relay_click", *group );
+ leds[0x76] = control;
+ controls.push_back( control );
+ controls_by_name["relay_click"] = control;
+ group->add( *control );
+
+}
+
+void Mackie::MackieSurface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
+{
+ if ( bs != press && bs != release )
+ {
+ mbh.update_led( button, none );
+ return;
+ }
+
+ LedState ls;
+ switch ( button.id() )
+ {
+
+ case 0x28: // io
+ switch ( bs ) {
+ case press: ls = mbh.io_press( button ); break;
+ case release: ls = mbh.io_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x29: // sends
+ switch ( bs ) {
+ case press: ls = mbh.sends_press( button ); break;
+ case release: ls = mbh.sends_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2a: // pan
+ switch ( bs ) {
+ case press: ls = mbh.pan_press( button ); break;
+ case release: ls = mbh.pan_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2b: // plugin
+ switch ( bs ) {
+ case press: ls = mbh.plugin_press( button ); break;
+ case release: ls = mbh.plugin_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2c: // eq
+ switch ( bs ) {
+ case press: ls = mbh.eq_press( button ); break;
+ case release: ls = mbh.eq_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2d: // dyn
+ switch ( bs ) {
+ case press: ls = mbh.dyn_press( button ); break;
+ case release: ls = mbh.dyn_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2e: // left
+ switch ( bs ) {
+ case press: ls = mbh.left_press( button ); break;
+ case release: ls = mbh.left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x2f: // right
+ switch ( bs ) {
+ case press: ls = mbh.right_press( button ); break;
+ case release: ls = mbh.right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x30: // channel_left
+ switch ( bs ) {
+ case press: ls = mbh.channel_left_press( button ); break;
+ case release: ls = mbh.channel_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x31: // channel_right
+ switch ( bs ) {
+ case press: ls = mbh.channel_right_press( button ); break;
+ case release: ls = mbh.channel_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x32: // flip
+ switch ( bs ) {
+ case press: ls = mbh.flip_press( button ); break;
+ case release: ls = mbh.flip_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x33: // edit
+ switch ( bs ) {
+ case press: ls = mbh.edit_press( button ); break;
+ case release: ls = mbh.edit_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x34: // name_value
+ switch ( bs ) {
+ case press: ls = mbh.name_value_press( button ); break;
+ case release: ls = mbh.name_value_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x35: // smpte_beats
+ switch ( bs ) {
+ case press: ls = mbh.smpte_beats_press( button ); break;
+ case release: ls = mbh.smpte_beats_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x36: // F1
+ switch ( bs ) {
+ case press: ls = mbh.F1_press( button ); break;
+ case release: ls = mbh.F1_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x37: // F2
+ switch ( bs ) {
+ case press: ls = mbh.F2_press( button ); break;
+ case release: ls = mbh.F2_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x38: // F3
+ switch ( bs ) {
+ case press: ls = mbh.F3_press( button ); break;
+ case release: ls = mbh.F3_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x39: // F4
+ switch ( bs ) {
+ case press: ls = mbh.F4_press( button ); break;
+ case release: ls = mbh.F4_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3a: // F5
+ switch ( bs ) {
+ case press: ls = mbh.F5_press( button ); break;
+ case release: ls = mbh.F5_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3b: // F6
+ switch ( bs ) {
+ case press: ls = mbh.F6_press( button ); break;
+ case release: ls = mbh.F6_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3c: // F7
+ switch ( bs ) {
+ case press: ls = mbh.F7_press( button ); break;
+ case release: ls = mbh.F7_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3d: // F8
+ switch ( bs ) {
+ case press: ls = mbh.F8_press( button ); break;
+ case release: ls = mbh.F8_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3e: // F9
+ switch ( bs ) {
+ case press: ls = mbh.F9_press( button ); break;
+ case release: ls = mbh.F9_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x3f: // F10
+ switch ( bs ) {
+ case press: ls = mbh.F10_press( button ); break;
+ case release: ls = mbh.F10_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x40: // F11
+ switch ( bs ) {
+ case press: ls = mbh.F11_press( button ); break;
+ case release: ls = mbh.F11_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x41: // F12
+ switch ( bs ) {
+ case press: ls = mbh.F12_press( button ); break;
+ case release: ls = mbh.F12_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x42: // F13
+ switch ( bs ) {
+ case press: ls = mbh.F13_press( button ); break;
+ case release: ls = mbh.F13_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x43: // F14
+ switch ( bs ) {
+ case press: ls = mbh.F14_press( button ); break;
+ case release: ls = mbh.F14_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x44: // F15
+ switch ( bs ) {
+ case press: ls = mbh.F15_press( button ); break;
+ case release: ls = mbh.F15_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x45: // F16
+ switch ( bs ) {
+ case press: ls = mbh.F16_press( button ); break;
+ case release: ls = mbh.F16_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x46: // shift
+ switch ( bs ) {
+ case press: ls = mbh.shift_press( button ); break;
+ case release: ls = mbh.shift_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x47: // option
+ switch ( bs ) {
+ case press: ls = mbh.option_press( button ); break;
+ case release: ls = mbh.option_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x48: // control
+ switch ( bs ) {
+ case press: ls = mbh.control_press( button ); break;
+ case release: ls = mbh.control_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x49: // cmd_alt
+ switch ( bs ) {
+ case press: ls = mbh.cmd_alt_press( button ); break;
+ case release: ls = mbh.cmd_alt_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4a: // on
+ switch ( bs ) {
+ case press: ls = mbh.on_press( button ); break;
+ case release: ls = mbh.on_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4b: // rec_ready
+ switch ( bs ) {
+ case press: ls = mbh.rec_ready_press( button ); break;
+ case release: ls = mbh.rec_ready_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4c: // undo
+ switch ( bs ) {
+ case press: ls = mbh.undo_press( button ); break;
+ case release: ls = mbh.undo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4d: // snapshot
+ switch ( bs ) {
+ case press: ls = mbh.snapshot_press( button ); break;
+ case release: ls = mbh.snapshot_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4e: // touch
+ switch ( bs ) {
+ case press: ls = mbh.touch_press( button ); break;
+ case release: ls = mbh.touch_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x4f: // redo
+ switch ( bs ) {
+ case press: ls = mbh.redo_press( button ); break;
+ case release: ls = mbh.redo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x50: // marker
+ switch ( bs ) {
+ case press: ls = mbh.marker_press( button ); break;
+ case release: ls = mbh.marker_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x51: // enter
+ switch ( bs ) {
+ case press: ls = mbh.enter_press( button ); break;
+ case release: ls = mbh.enter_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x52: // cancel
+ switch ( bs ) {
+ case press: ls = mbh.cancel_press( button ); break;
+ case release: ls = mbh.cancel_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x53: // mixer
+ switch ( bs ) {
+ case press: ls = mbh.mixer_press( button ); break;
+ case release: ls = mbh.mixer_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x54: // frm_left
+ switch ( bs ) {
+ case press: ls = mbh.frm_left_press( button ); break;
+ case release: ls = mbh.frm_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x55: // frm_right
+ switch ( bs ) {
+ case press: ls = mbh.frm_right_press( button ); break;
+ case release: ls = mbh.frm_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x56: // loop
+ switch ( bs ) {
+ case press: ls = mbh.loop_press( button ); break;
+ case release: ls = mbh.loop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x57: // punch_in
+ switch ( bs ) {
+ case press: ls = mbh.punch_in_press( button ); break;
+ case release: ls = mbh.punch_in_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x58: // punch_out
+ switch ( bs ) {
+ case press: ls = mbh.punch_out_press( button ); break;
+ case release: ls = mbh.punch_out_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x59: // home
+ switch ( bs ) {
+ case press: ls = mbh.home_press( button ); break;
+ case release: ls = mbh.home_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5a: // end
+ switch ( bs ) {
+ case press: ls = mbh.end_press( button ); break;
+ case release: ls = mbh.end_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5b: // rewind
+ switch ( bs ) {
+ case press: ls = mbh.rewind_press( button ); break;
+ case release: ls = mbh.rewind_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5c: // ffwd
+ switch ( bs ) {
+ case press: ls = mbh.ffwd_press( button ); break;
+ case release: ls = mbh.ffwd_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5d: // stop
+ switch ( bs ) {
+ case press: ls = mbh.stop_press( button ); break;
+ case release: ls = mbh.stop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5e: // play
+ switch ( bs ) {
+ case press: ls = mbh.play_press( button ); break;
+ case release: ls = mbh.play_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x5f: // record
+ switch ( bs ) {
+ case press: ls = mbh.record_press( button ); break;
+ case release: ls = mbh.record_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x60: // cursor_up
+ switch ( bs ) {
+ case press: ls = mbh.cursor_up_press( button ); break;
+ case release: ls = mbh.cursor_up_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x61: // cursor_down
+ switch ( bs ) {
+ case press: ls = mbh.cursor_down_press( button ); break;
+ case release: ls = mbh.cursor_down_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x62: // cursor_left
+ switch ( bs ) {
+ case press: ls = mbh.cursor_left_press( button ); break;
+ case release: ls = mbh.cursor_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x63: // cursor_right
+ switch ( bs ) {
+ case press: ls = mbh.cursor_right_press( button ); break;
+ case release: ls = mbh.cursor_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x64: // zoom
+ switch ( bs ) {
+ case press: ls = mbh.zoom_press( button ); break;
+ case release: ls = mbh.zoom_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x65: // scrub
+ switch ( bs ) {
+ case press: ls = mbh.scrub_press( button ); break;
+ case release: ls = mbh.scrub_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x66: // user_a
+ switch ( bs ) {
+ case press: ls = mbh.user_a_press( button ); break;
+ case release: ls = mbh.user_a_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x67: // user_b
+ switch ( bs ) {
+ case press: ls = mbh.user_b_press( button ); break;
+ case release: ls = mbh.user_b_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ }
+ mbh.update_led( button, ls );
+}
diff --git a/libs/surfaces/mackie/mackie_surface.h b/libs/surfaces/mackie/mackie_surface.h
new file mode 100644
index 0000000000..735cbc5851
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_surface.h
@@ -0,0 +1,27 @@
+#ifndef mackie_surface_mackie_h
+#define mackie_surface_mackie_h
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "surface.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler;
+
+class MackieSurface : public Surface
+{
+public:
+ MackieSurface( uint32_t max_strips ) : Surface( max_strips )
+ {
+ }
+
+ virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
+ virtual void init_controls();
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/midi_byte_array.cc b/libs/surfaces/mackie/midi_byte_array.cc
new file mode 100644
index 0000000000..192af6a1ce
--- /dev/null
+++ b/libs/surfaces/mackie/midi_byte_array.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 "midi_byte_array.h"
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <cstdarg>
+#include <iomanip>
+
+using namespace std;
+
+MidiByteArray::MidiByteArray( size_t size, MIDI::byte array[] )
+: std::vector<MIDI::byte>()
+{
+ for ( size_t i = 0; i < size; ++i )
+ {
+ push_back( array[i] );
+ }
+}
+
+MidiByteArray::MidiByteArray( size_t count, MIDI::byte first, ... )
+: vector<MIDI::byte>()
+{
+ push_back( first );
+ va_list var_args;
+ va_start( var_args, first );
+ for ( size_t i = 1; i < count; ++i )
+ {
+ MIDI::byte b = va_arg( var_args, int );
+ push_back( b );
+ }
+ va_end( var_args );
+}
+
+boost::shared_array<MIDI::byte> MidiByteArray::bytes() const
+{
+ MIDI::byte * buf = new MIDI::byte[size()];
+ const_iterator it = begin();
+ for( MIDI::byte * ptr = buf; it != end(); ++it )
+ {
+ *ptr++ = *it;
+ }
+ return boost::shared_array<MIDI::byte>( buf );
+}
+
+void MidiByteArray::copy( size_t count, MIDI::byte * arr )
+{
+ for( size_t i = 0; i < count; ++i )
+ {
+ push_back( arr[i] );
+ }
+}
+
+MidiByteArray & operator << ( MidiByteArray & mba, const MIDI::byte & b )
+{
+ mba.push_back( b );
+ return mba;
+}
+
+MidiByteArray & operator << ( MidiByteArray & mba, const MidiByteArray & barr )
+{
+ back_insert_iterator<MidiByteArray> bit( mba );
+ copy( barr.begin(), barr.end(), bit );
+ return mba;
+}
+
+ostream & operator << ( ostream & os, const MidiByteArray & mba )
+{
+ os << "[";
+ char fill = os.fill('0');
+ for( MidiByteArray::const_iterator it = mba.begin(); it != mba.end(); ++it )
+ {
+ if ( it != mba.begin() ) os << " ";
+ os << hex << setw(2) << (int)*it;
+ }
+ os.fill( fill );
+ os << dec;
+ os << "]";
+ return os;
+}
diff --git a/libs/surfaces/mackie/midi_byte_array.h b/libs/surfaces/mackie/midi_byte_array.h
new file mode 100644
index 0000000000..e77ece1b88
--- /dev/null
+++ b/libs/surfaces/mackie/midi_byte_array.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 midi_byte_array_h
+#define midi_byte_array_h
+
+#include <iostream>
+#include <vector>
+
+#include <boost/shared_array.hpp>
+
+//#include <midi++/types.h>
+namespace MIDI {
+ typedef unsigned char byte;
+}
+
+/**
+ To make building arrays of bytes easier. Thusly:
+
+ MidiByteArray mba;
+ mba << 0xf0 << 0x00 << 0xf7;
+
+ MidiByteArray buf;
+ buf << mba;
+
+ MidiByteArray direct( 3, 0xf0, 0x00, 0xf7 );
+
+ cout << mba << endl;
+ cout << buf << endl;
+ cout << direct << endl;
+
+ will all result in "f0 00 f7" being output to stdout
+*/
+class MidiByteArray : public std::vector<MIDI::byte>
+{
+public:
+ MidiByteArray() : std::vector<MIDI::byte>() {}
+
+ MidiByteArray( size_t count, MIDI::byte array[] );
+
+ /**
+ Accepts a preceding count, and then a list of bytes
+ */
+ MidiByteArray( size_t count, MIDI::byte first, ... );
+
+ /// return smart pointer to a copy of the bytes
+ boost::shared_array<MIDI::byte> bytes() const;
+
+ /// copy the given number of bytes from the given array
+ void copy( size_t count, MIDI::byte arr[] );
+};
+
+/// append the given byte to the end of the array
+MidiByteArray & operator << ( MidiByteArray & mba, const MIDI::byte & b );
+
+/// append the given array to the end of this array
+MidiByteArray & operator << ( MidiByteArray & mba, const MidiByteArray & barr );
+
+/// output the bytes as hex to the given stream
+std::ostream & operator << ( std::ostream & os, const MidiByteArray & mba );
+
+#endif
diff --git a/libs/surfaces/mackie/route_signal.cc b/libs/surfaces/mackie/route_signal.cc
new file mode 100644
index 0000000000..d77d0520a1
--- /dev/null
+++ b/libs/surfaces/mackie/route_signal.cc
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 "route_signal.h"
+
+#include <ardour/route.h>
+#include <ardour/track.h>
+#include <ardour/panner.h>
+
+#include "mackie_control_protocol.h"
+
+#include <stdexcept>
+
+using namespace Mackie;
+
+void RouteSignal::connect()
+{
+ if ( _strip.has_solo() )
+ _solo_changed_connection = _route.solo_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) );
+
+ if ( _strip.has_mute() )
+ _mute_changed_connection = _route.mute_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) );
+
+ if ( _strip.has_gain() )
+ _gain_changed_connection = _route.gain_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) );
+
+ _name_changed_connection = _route.name_changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
+
+ if ( _route.panner().size() == 1 )
+ {
+ _panner_changed_connection = _route.panner()[0]->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_panner_changed ), this ) );
+ }
+
+ try
+ {
+ _record_enable_changed_connection =
+ dynamic_cast<ARDOUR::Track&>( _route ).rec_enable_control().Changed
+ .connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_record_enable_changed ), this ) )
+ ;
+ }
+ catch ( std::bad_cast & )
+ {
+ // this should catch the dynamic_cast to Track, if what we're working
+ // with can't be record-enabled
+ }
+
+ // TODO
+ // active_changed
+ // SelectedChanged
+ // RemoteControlIDChanged. Better handled at Session level.
+}
+
+void RouteSignal::disconnect()
+{
+ _solo_changed_connection.disconnect();
+ _mute_changed_connection.disconnect();
+ _gain_changed_connection.disconnect();
+ _name_changed_connection.disconnect();
+ _panner_changed_connection.disconnect();
+ _record_enable_changed_connection.disconnect();
+}
+
+void RouteSignal::notify_all()
+{
+ if ( _strip.has_solo() )
+ _mcp.notify_solo_changed( this );
+
+ if ( _strip.has_mute() )
+ _mcp.notify_mute_changed( this );
+
+ if ( _strip.has_gain() )
+ _mcp.notify_gain_changed( this );
+
+ _mcp.notify_name_changed( &_route, this );
+
+ if ( _strip.has_vpot() )
+ _mcp.notify_panner_changed( this );
+
+ if ( _strip.has_recenable() )
+ _mcp.notify_record_enable_changed( this );
+}
diff --git a/libs/surfaces/mackie/route_signal.h b/libs/surfaces/mackie/route_signal.h
new file mode 100644
index 0000000000..0239980fd4
--- /dev/null
+++ b/libs/surfaces/mackie/route_signal.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 route_signal_h
+#define route_signal_h
+
+#include <sigc++/sigc++.h>
+
+class MackieControlProtocol;
+
+namespace ARDOUR {
+ class Route;
+}
+
+namespace Mackie
+{
+
+class Strip;
+class MackiePort;
+
+/**
+ This class is intended to easily create and destroy the set of
+ connections from a route to a control surface strip. Instantiating
+ it will connect the signals, and destructing it will disconnect
+ the signals.
+*/
+class RouteSignal
+{
+public:
+ RouteSignal( ARDOUR::Route & route, MackieControlProtocol & mcp, Strip & strip, MackiePort & port )
+ : _route( route ), _mcp( mcp ), _strip( strip ), _port( port )
+ {
+ connect();
+ }
+
+ ~RouteSignal()
+ {
+ disconnect();
+ }
+
+ void connect();
+ void disconnect();
+
+ // call all signal handlers manually
+ void notify_all();
+
+ const ARDOUR::Route & route() const { return _route; }
+ Strip & strip() { return _strip; }
+ MackiePort & port() { return _port; }
+
+private:
+ ARDOUR::Route & _route;
+ MackieControlProtocol & _mcp;
+ Strip & _strip;
+ MackiePort & _port;
+
+ sigc::connection _solo_changed_connection;
+ sigc::connection _mute_changed_connection;
+ sigc::connection _record_enable_changed_connection;
+ sigc::connection _gain_changed_connection;
+ sigc::connection _name_changed_connection;
+ sigc::connection _panner_changed_connection;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/scripts/bank.rb b/libs/surfaces/mackie/scripts/bank.rb
new file mode 100644
index 0000000000..e1482545ee
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/bank.rb
@@ -0,0 +1,32 @@
+#! /usr/bin/ruby
+
+class Bank
+ attr_accessor :routes, :strips, :current
+
+ def initialize( routes = 17, strips = 8, current = 0 )
+ @routes = routes
+ @strips = strips
+ @current = current
+ end
+
+ def left
+ new_initial = current - routes
+ if new_initial < 0
+ new_initial = 0
+ end
+ current = new_initial
+ self
+ end
+
+ def right
+ delta = routes - ( strips + current ) - 1
+ puts "delta: #{delta}"
+ if delta > strips
+ delta = strips
+ end
+ @current += delta
+ self
+ end
+end
+
+b=Bank.new
diff --git a/libs/surfaces/mackie/scripts/bcf-controls.csv b/libs/surfaces/mackie/scripts/bcf-controls.csv
new file mode 100644
index 0000000000..6a6d66f6ac
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/bcf-controls.csv
@@ -0,0 +1,96 @@
+type,count,group,name,switch,led,id
+# faders
+fader,7,strip,gain,1,0,0x00
+fader,1,master,gain,1,0,0x07
+
+# pots
+pot,7,strip,vpot,1,1,0x10
+pot,1,,jog,1,0,0x17
+pot,1,,external,1,0,0x2e
+
+# strip buttons
+button,7,strip,recenable,1,1,0x18
+button,7,strip,solo,1,1,0x20
+button,7,strip,mute,1,1,0x10
+button,7,strip,select,1,1,0x0
+button,7,strip,vselect,1,0,0x08
+
+# overlay buttons
+button,1,assignment,io,1,1,0x28
+button,1,assignment,sends,1,1,0x5a
+button,1,assignment,pan,1,1,0x59
+button,1,assignment,plugin,1,1,0x57
+button,1,assignment,eq,1,1,0x58
+button,1,assignment,dyn,1,1,0x2d
+button,1,bank,left,1,0,0x2e
+button,1,bank,right,1,0,0x2f
+button,1,bank,channel_left,1,0,0x30
+button,1,bank,channel_right,1,0,0x31
+button,1,,flip,1,1,0x32
+button,1,,edit,1,1,0x56
+
+button,1,display,name_value,1,0,0x34
+button,1,display,smpte_beats,1,0,0x35
+button,1,,F1,1,0,0x36
+button,1,,F2,1,0,0x37
+button,1,,F3,1,0,0x38
+button,1,,F4,1,0,0x39
+button,1,,F5,1,0,0x3a
+button,1,,F6,1,0,0x3b
+button,1,,F7,1,0,0x3c
+button,1,,F8,1,0,0x3d
+button,1,,F9,1,0,0x3e
+button,1,,F10,1,0,0x3f
+button,1,,F11,1,0,0x40
+button,1,,F12,1,0,0x41
+button,1,,F13,1,0,0x42
+button,1,,F14,1,0,0x43
+button,1,,F15,1,0,0x44
+button,1,,F16,1,0,0x45
+# turn on/off all solos
+button,1,,global_solo,1,0,0x27
+button,1,modifiers,option,1,0,0x47
+button,1,modifiers,control,1,0,0x48
+button,1,modifiers,cmd_alt,1,0,0x49
+button,1,automation,on,1,1,0x4a
+button,1,automation,rec_ready,1,1,0x4b
+button,1,functions,undo,1,1,0x4c
+button,1,automation,snapshot,1,1,0x4d
+button,1,automation,touch,1,1,0x4e
+button,1,functions,redo,1,1,0x4f
+button,1,functions,marker,1,1,0x50
+button,1,functions,enter,1,1,0x51
+button,1,functions,cancel,1,0,0x52
+button,1,functions,mixer,1,0,0x53
+button,1,transport,frm_left,1,1,0x54
+button,1,transport,frm_right,1,1,0x55
+button,1,transport,loop,1,1,0x46
+button,1,transport,punch_in,1,1,0x2c
+button,1,transport,punch_out,1,1,0x2b
+button,1,transport,home,1,1,0x2a
+button,1,transport,end,1,1,0x29
+
+# transport buttons
+button,1,transport,"rewind",1,1,0x5b
+button,1,transport,"ffwd",1,1,0x5c
+button,1,transport,"stop",1,1,0x5d
+button,1,transport,"play",1,1,0x5e
+button,1,transport,"record",1,1,0x1f
+button,1,cursor,"cursor_up",1,0,0x60
+button,1,cursor,"cursor_down",1,0,0x61
+button,1,cursor,"cursor_left",1,0,0x62
+button,1,cursor,"cursor_right",1,0,0x63
+button,1,,"zoom",1,1,0x64
+button,1,,"scrub",1,1,0x65
+button,1,user,"user_a",1,0,0x66
+button,1,user,"user_b",1,0,0x67
+
+button,7,strip,"fader_touch",1,0,0x68
+button,1,master,"fader_touch",1,0,0x6f
+button,1,master,mute,1,0,0x17
+button,1,,clicking,1,1,0x33
+
+button,1,,"smpte",0,1,0x71
+button,1,,"beats",0,1,0x72
+button,1,,"solo",0,1,0x73
+button,1,,"relay_click",0,1,0x76
diff --git a/libs/surfaces/mackie/scripts/controls.rb b/libs/surfaces/mackie/scripts/controls.rb
new file mode 100644
index 0000000000..b56fd6010d
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/controls.rb
@@ -0,0 +1,208 @@
+#! /usr/bin/ruby
+# Copyright (C) 2006,2007 John Anderson
+
+# 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.
+
+require 'faster_csv'
+require 'mackie.rb'
+
+class Control
+ attr_accessor :id, :led, :group, :name, :ordinal, :switch
+
+ def initialize( obj, group )
+ @id = obj.id
+ @name = obj.name
+ @ordinal = obj.ordinal
+ @switch = obj.switch
+ @group = group
+ end
+
+ def ordinal_name
+ end
+end
+
+class Fader < Control
+ def self.midi_zero_byte
+ 0xe0
+ end
+
+ def self.mask_for_id( bytes )
+ bytes[0] & 0b00001111
+ end
+end
+
+class Button < Control
+ def self.midi_zero_byte
+ 0x90
+ end
+
+ def self.mask_for_id( bytes )
+ bytes[1]
+ end
+end
+
+class Led < Control
+end
+
+class LedRing < Led
+end
+
+class Pot < Control
+ def self.midi_zero_byte
+ 0xb0
+ end
+
+ def self.mask_for_id( bytes )
+ bytes[1] & 0b00011111
+ end
+
+ def led=( rhs )
+ @led = LedRing.new( rhs, group )
+ end
+end
+
+class Group < Array
+ attr_accessor :name, :controls
+
+ def initialize( name )
+ @name = name
+ end
+
+ def add_control( control )
+ @controls ||= Array.new
+ @controls << control
+ end
+end
+
+class Strip < Group
+
+ attr_accessor :ordinal
+ def initialize( name, ordinal )
+ super( name )
+ @ordinal = ordinal
+ end
+
+ def name
+ @name == 'master' ? @name : "#{@name}_#{@ordinal}"
+ end
+
+ def is_master
+ name == 'master'
+ end
+
+end
+
+types = { 0xe0 => Fader, 0x90 => Button, 0xb0 => Pot }
+
+# number of controls, name, switch, led, id
+# anything that doesn't have the correct number
+# of columns will be ignored
+# actually, 'switch' means it generates data
+# whereas 'led' means it receives data
+
+class Row
+ attr_accessor :count, :name, :switch, :led, :start_id, :type, :group
+ attr_accessor :id, :ordinal_name, :ordinal_group, :ordinal
+
+ def initialize( hash )
+ @count = hash['count'].to_i
+ @name = hash['name']
+ @switch = hash['switch'].to_b
+ @led = hash['led'].to_b
+ @start_id = hash['id'].hex
+ @type = hash['type']
+ @group = hash['group']
+
+ @hash = hash
+ end
+
+ def each_ordinal( &block )
+ for i in 0...count
+ @ordinal = i + 1
+ @ordinal_name = count > 1 ? "#{name}_#{ordinal}" : name
+ @ordinal_group = count > 1 ? "#{group}_#{ordinal}" : group
+ @id = start_id + i
+
+ @hash['ordinal_name'] = @ordinal_name
+ @hash['ordinal_group'] = @ordinal_group
+
+ yield( self )
+ end
+ self
+ end
+
+ def to_hash
+ @hash
+ end
+end
+
+class Surface
+ attr_reader :groups, :controls_by_id, :types, :midis, :controls, :name
+
+ def initialize( name = 'none' )
+ @name = name
+ @types = Hash.new
+ @groups = Hash.new
+ @controls = Array.new
+ @controls_by_id = Hash.new
+ @midis = Hash.new
+ end
+
+ def add_or_create_group( name, ordinal = nil )
+ if name.nil?
+ @groups['none'] = Group.new('none')
+ else
+ group = name =~ /strip/ || name == 'master' ? Strip.new( name, ordinal ) : Group.new( name )
+ @groups[group.name] ||= group
+ end
+ end
+
+ def parse( control_data )
+ FasterCSV.parse( control_data, :headers => true ) do |csv_row|
+ next if csv_row.entries.size < 5 || csv_row[0] =~ /^\s*#/ || csv_row['id'].nil?
+ row = Row.new( csv_row )
+
+ row.each_ordinal do |row|
+ group = add_or_create_group( row.group, row.ordinal )
+ if row.switch
+ # for controls
+ control = eval "#{row.type.capitalize}.new( row, group )"
+
+ # for controls with leds
+ control.led = Led.new( row, group ) if row.led
+ else
+ # for LED-only entries
+ if row.led
+ control = Led.new( row, group )
+ control.led = control
+ end
+ end
+
+ # add the new control to the various lookups
+ @controls_by_id[row.id] = control
+ @controls << control
+ group << control
+
+ # add incoming midi bytes
+ if row.switch
+ types[control.class.midi_zero_byte] = control.class
+ midis[control.class.midi_zero_byte] ||= Hash.new
+ midis[control.class.midi_zero_byte][row.id] = control
+ end
+ end
+ end
+ self
+ end
+end
diff --git a/libs/surfaces/mackie/scripts/dump.rb b/libs/surfaces/mackie/scripts/dump.rb
new file mode 100755
index 0000000000..f1e341fb34
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/dump.rb
@@ -0,0 +1,11 @@
+#! /usr/bin/ruby
+
+while !File.exist? ARGV[0]
+ sleep 0.010
+end
+
+file = File.open ARGV[0], 'r'
+
+while bytes = file.sysread( 3 )
+ puts "%02x %02x %02x" % [ bytes[0], bytes[1], bytes[2] ]
+end
diff --git a/libs/surfaces/mackie/scripts/generate-button-handlers-cc.erb b/libs/surfaces/mackie/scripts/generate-button-handlers-cc.erb
new file mode 100644
index 0000000000..62bc65d0c3
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/generate-button-handlers-cc.erb
@@ -0,0 +1,59 @@
+<%#
+ Copyright (C) 2006,2007 John Anderson
+
+ 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.
+-%>
+<%-
+require 'controls.rb'
+
+sf = Surface.new
+sf.parse( File.open "mackie-controls.csv" )
+buttons = sf.controls.find_all{|x| x.class == Button && x.group.class != Strip}
+-%>
+/*
+ Generated by scripts/generate-button-handlers.erb
+*/
+#include "mackie_button_handler.h"
+#include "controls.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace Mackie;
+
+LedState MackieButtonHandler::default_button_press( Button & button )
+{
+ cout << "press: " << button << endl;
+ return on;
+}
+LedState MackieButtonHandler::default_button_release( Button & button )
+{
+ cout << "release: " << button << endl;
+ return off;
+}
+
+<%-
+buttons.each do |button|
+%>
+LedState MackieButtonHandler::<%=button.name%>_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::<%=button.name%>_release( Button & button )
+{
+ return default_button_release( button );
+}
+<% end %>
diff --git a/libs/surfaces/mackie/scripts/generate-button-handlers-h.erb b/libs/surfaces/mackie/scripts/generate-button-handlers-h.erb
new file mode 100644
index 0000000000..605b6c29dc
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/generate-button-handlers-h.erb
@@ -0,0 +1,54 @@
+<%#
+ Copyright (C) 2006,2007 John Anderson
+
+ 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.
+-%>
+<%-
+require 'controls.rb'
+
+sf = Surface.new
+sf.parse( File.open "mackie-controls.csv" )
+buttons = sf.controls.find_all{|x| x.class == Button && x.group.class != Strip}
+-%>
+#ifndef mackie_button_handler_h
+#define mackie_button_handler_h
+/*
+ Generated by scripts/generate-button-handlers.erb
+*/
+
+#include "types.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler
+{
+public:
+ virtual ~MackieButtonHandler() {}
+
+ virtual LedState default_button_press( Button & button );
+ virtual LedState default_button_release( Button & button );
+
+ virtual void update_led( Button & button, LedState ls ) = 0;
+
+<%- buttons.each do |button| %>
+ virtual LedState <%=button.name%>_press( Button & );
+ virtual LedState <%=button.name%>_release( Button & );
+<% end %>
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/scripts/generate-surface.rb b/libs/surfaces/mackie/scripts/generate-surface.rb
new file mode 100755
index 0000000000..c6a028804a
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/generate-surface.rb
@@ -0,0 +1,26 @@
+#! /usr/bin/ruby
+
+require 'erb'
+
+require File.dirname(__FILE__) + '/controls.rb'
+
+cc_template = ''
+File.open( File.dirname(__FILE__) + "/surface-cc-template.erb", "r" ) { |f| cc_template = f.read }
+
+h_template = ''
+File.open( File.dirname(__FILE__) + "/surface-h-template.erb", "r" ) { |f| h_template = f.read }
+
+sf = Surface.new( ARGV[0] )
+control_data = ''
+File.open( File.dirname(__FILE__) + "/#{sf.name.downcase}-controls.csv", "r") { |f| control_data = f.read }
+sf.parse control_data
+
+@result = ""
+erb = ERB.new( cc_template , 0, "%<>-", "@result" )
+erb.result
+File.open( "#{sf.name.downcase}_surface.cc", "w" ) { |f| f.write @result }
+
+erb = ERB.new( h_template , 0, "%<>-", "@result" )
+erb.result
+File.open( "#{sf.name.downcase}_surface.h", "w" ) { |f| f.write @result }
+
diff --git a/libs/surfaces/mackie/scripts/host.rb b/libs/surfaces/mackie/scripts/host.rb
new file mode 100755
index 0000000000..8972cba137
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/host.rb
@@ -0,0 +1,133 @@
+#! /usr/bin/ruby
+# Copyright (C) 2006,2007 John Anderson
+
+# 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.
+
+require 'controls.rb'
+require 'mackie.rb'
+
+while !File.exist? ARGV[0]
+ sleep 0.010
+end
+
+#mapping_csv = ARGV[1] || "mackie-controls.csv"
+mapping_csv = ARGV[1]
+puts "mapping_csv: #{mapping_csv}"
+puts ""
+
+file = File.open ARGV[0], 'r+'
+mck = Mackie.new( file )
+
+# send device query
+response = mck.sysex( "\x00" )
+puts "response: #{response.to_hex}"
+
+# decode host connection query
+status = response[0]
+if status != 1
+ puts "expected 01, got " + response.to_hex.inspect
+ exit(1)
+end
+serial = response[1..7]
+challenge = response[8..11]
+puts <<EOF
+serial: #{serial.to_hex.inspect}
+challenge: #{challenge.to_hex.inspect}
+EOF
+
+# send host connection reply
+response = mck.sysex( "\x02" + serial.pack('C*') + challenge.pack('C*') )
+
+# decode host connection confirmation
+status = response[0]
+if status != 3
+ puts "expected 03, got " + response.to_hex.inspect
+ exit(1)
+end
+
+serial = response[1..7]
+puts <<EOF
+serial: #{serial.to_hex.inspect}
+EOF
+
+# faders to minimum. bcf2000 doesn't respond
+#file.write( hdr + "\x61\xf7" )
+
+# all leds off. bcf2000 doesn't respond
+#file.write( hdr + "\x62\xf7" )
+
+# get version. comes back as ASCII bytes
+version = mck.sysex( "\x13\x00" )
+puts "version: #{version.map{|x| x.chr}}"
+
+# write a welcome message. bcf2000 responds with exact
+# string but doesn't display anything
+# 0 offset,
+#~ file.write hdr + "\x12\x3fLCDE\xf7"
+#~ file.flush
+#~ answer = read_sysex file
+#~ puts "answer: #{answer[hdr.length..-1].map{|x| x.chr}}"
+
+# write to BBT display
+#~ file.write hdr + "\x10LCDE\xf7"
+#~ file.flush
+#~ bbt = []
+#~ while ( nc = file.read( 1 ) )[0] != 0xf7
+ #~ bbt << nc[0]
+#~ end
+#~ puts "bbt: #{bbt[hdr.length..-1].map{|x| x.chr}}"
+
+# write 7-segment display
+#~ file.write hdr + "\x11LCDE\xf7"
+#~ file.flush
+
+# go offline. bcf2000 doesn't respond
+#~ file.write( hdr + "\x0f\x7f\xf7" )
+#~ file.flush
+
+sf = Surface.new
+control_data = ""
+File.open( mapping_csv ) { |f| control_data = f.read }
+sf.parse( control_data )
+
+# send all faders to 0, but bounce them first
+# otherwise the bcf gets confused
+sf.midis[0xe0].values.find_all{|x| x.class == Fader}.each do |x|
+ bytes = Array.new
+ bytes[0] = 0xe0 + x.ordinal - 1
+ bytes[1] = 0x1
+ bytes[2] = 0x1
+ file.write bytes.pack( 'C*' )
+ bytes[0] = 0xe0 + x.ordinal - 1
+ bytes[1] = 0x0
+ bytes[2] = 0x0
+ file.write bytes.pack( 'C*' )
+end
+file.flush
+
+# respond to control movements
+while bytes = mck.file.read( 3 )
+ print "received: %02.x %02.x %02.x" % [ bytes[0], bytes[1], bytes[2] ]
+ midi_type = bytes[0] & 0b11110000
+
+ control_id = sf.types[midi_type].mask_for_id( bytes )
+ control = sf.midis[midi_type][control_id]
+
+ print " Control Type: %-7s, " % sf.types[midi_type]
+ print "id: %4i" % control_id
+ print ", control: %15s" % ( control ? control.name : "nil control" )
+ print ", %15s" % ( control ? control.group.name : "nil group" )
+ print "\n"
+end
diff --git a/libs/surfaces/mackie/scripts/mackie-controls.csv b/libs/surfaces/mackie/scripts/mackie-controls.csv
new file mode 100644
index 0000000000..5dbb6297f8
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/mackie-controls.csv
@@ -0,0 +1,93 @@
+type,count,group,name,switch,led,id
+# faders
+fader,8,strip,gain,1,0,0x00
+fader,1,master,gain,1,0,0x08
+
+# pots
+pot,8,strip,vpot,1,1,0x10
+pot,1,,jog,1,0,0x3c
+pot,1,,external,1,0,0x2e
+
+# strip buttons
+button,8,strip,recenable,1,1,0x0
+button,8,strip,solo,1,1,0x08
+button,8,strip,mute,1,1,0x10
+button,8,strip,select,1,1,0x18
+button,8,strip,vselect,1,0,0x20
+
+# overlay buttons
+button,1,assignment,io,1,1,0x28
+button,1,assignment,sends,1,1,0x29
+button,1,assignment,pan,1,1,0x2a
+button,1,assignment,plugin,1,1,0x2b
+button,1,assignment,eq,1,1,0x2c
+button,1,assignment,dyn,1,1,0x2d
+button,1,bank,left,1,0,0x2e
+button,1,bank,right,1,0,0x2f
+button,1,bank,channel_left,1,0,0x30
+button,1,bank,channel_right,1,0,0x31
+button,1,,flip,1,1,0x32
+button,1,,edit,1,1,0x33
+
+button,1,display,name_value,1,0,0x34
+button,1,display,smpte_beats,1,0,0x35
+button,1,,F1,1,0,0x36
+button,1,,F2,1,0,0x37
+button,1,,F3,1,0,0x38
+button,1,,F4,1,0,0x39
+button,1,,F5,1,0,0x3a
+button,1,,F6,1,0,0x3b
+button,1,,F7,1,0,0x3c
+button,1,,F8,1,0,0x3d
+button,1,,F9,1,0,0x3e
+button,1,,F10,1,0,0x3f
+button,1,,F11,1,0,0x40
+button,1,,F12,1,0,0x41
+button,1,,F13,1,0,0x42
+button,1,,F14,1,0,0x43
+button,1,,F15,1,0,0x44
+button,1,,F16,1,0,0x45
+button,1,modifiers,shift,1,0,0x46
+button,1,modifiers,option,1,0,0x47
+button,1,modifiers,control,1,0,0x48
+button,1,modifiers,cmd_alt,1,0,0x49
+button,1,automation,on,1,1,0x4a
+button,1,automation,rec_ready,1,1,0x4b
+button,1,functions,undo,1,1,0x4c
+button,1,automation,snapshot,1,1,0x4d
+button,1,automation,touch,1,1,0x4e
+button,1,functions,redo,1,1,0x4f
+button,1,functions,marker,1,1,0x50
+button,1,functions,enter,1,1,0x51
+button,1,functions,cancel,1,0,0x52
+button,1,functions,mixer,1,0,0x53
+button,1,transport,frm_left,1,1,0x54
+button,1,transport,frm_right,1,1,0x55
+button,1,transport,loop,1,1,0x56
+button,1,transport,punch_in,1,1,0x57
+button,1,transport,punch_out,1,1,0x58
+button,1,transport,home,1,1,0x59
+button,1,transport,end,1,1,0x5a
+
+# transport buttons
+button,1,transport,"rewind",1,1,0x5b
+button,1,transport,"ffwd",1,1,0x5c
+button,1,transport,"stop",1,1,0x5d
+button,1,transport,"play",1,1,0x5e
+button,1,transport,"record",1,1,0x5f
+button,1,cursor,"cursor_up",1,0,0x60
+button,1,cursor,"cursor_down",1,0,0x61
+button,1,cursor,"cursor_left",1,0,0x62
+button,1,cursor,"cursor_right",1,0,0x63
+button,1,,"zoom",1,1,0x64
+button,1,,"scrub",1,1,0x65
+button,1,user,"user_a",1,0,0x66
+button,1,user,"user_b",1,0,0x67
+
+button,8,strip,"fader_touch",1,0,0x68
+button,1,master,"fader_touch",1,0,0x70
+
+button,1,,"smpte",0,1,0x71
+button,1,,"beats",0,1,0x72
+button,1,,"solo",0,1,0x73
+button,1,,"relay_click",0,1,0x76
diff --git a/libs/surfaces/mackie/scripts/mackie.rb b/libs/surfaces/mackie/scripts/mackie.rb
new file mode 100644
index 0000000000..4c4080ad10
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/mackie.rb
@@ -0,0 +1,119 @@
+class String
+ def to_bytes
+ arr = []
+ each_byte{|x| arr << x}
+ arr
+ end
+end
+
+class Array
+ def to_hex
+ map{|x| "%2.0x" % x}
+ end
+
+ alias as_hex to_hex
+end
+
+class String
+ def to_b
+ to_i != 0 || %w{true t yes y}.include?( self.downcase )
+ end
+end
+
+class Fixnum
+ def to_hex
+ "%02x" % self
+ end
+end
+
+class Mackie
+ attr_accessor :file
+
+ def initialize( file )
+ @file = file
+ end
+
+ # send and receive a sysex message
+ # after wrapping in the header and the eox byte
+ def sysex( msg )
+ puts "Mackie write: #{msg.unpack('C*').to_hex.inspect}"
+ write_sysex( msg )
+ response = read_sysex
+ puts "Mackie response: #{response.to_hex.inspect}"
+ response[5..-1]
+ end
+
+ # returns an array of bytes
+ def read_sysex
+ buf = []
+ while ( nc = @file.read( 1 ) )[0] != 0xf7
+ buf << nc[0]
+ end
+ buf
+ end
+
+ # send and flush a sysex message
+ # after wrapping in the header and the eox byte
+ def write_sysex( msg )
+ @file.write( hdrlc + msg + "\xf7" )
+ @file.flush
+ end
+
+ def write( msg )
+ @file.write msg
+ @file.flush
+ end
+
+ def translate_seven_segment( char )
+ case char
+ when 0x40..0x60
+ char - 0x40
+ when 0x21..0x3f
+ char
+ else
+ 0x00
+ end
+ end
+
+ # display the msg (which can be only 2 characters)
+ # append the number of stops. Options are '..', '. ', '. ', ' '
+ def two_char( msg, stops = ' ' )
+ two = Array.new
+ two << translate_seven_segment( msg.upcase[0] )
+ two << translate_seven_segment( msg.upcase[1] )
+
+ two[0] += 0x40 if stops[0] == '.'[0]
+ two[1] += 0x40 if stops[1] == '.'[0]
+
+ midi_msg = [0xb0, 0x4a, two[1], 0x4b, two[0] ]
+ write midi_msg.pack( 'C*' )
+ end
+
+ # send and receive the device initialisation
+ def init
+ response = sysex( "\x00" )
+
+ # decode host connection query
+ status = response[0]
+ raise( "expected 01, got " + response.inspect ) if status != 1
+
+ serial = response[1..7]
+ challenge = response[8..11]
+
+ # send host connection reply
+ reply = "\x02" + serial.pack('C*') + challenge.pack('C*')
+ response = sysex reply
+
+ # decode host connection confirmation
+ status = response[0]
+ raise ( "expected 03, got " + response.inspect ) if status != 3
+ end
+
+ def hdrlc
+ "\xf0\x00\x00\x66\x10"
+ end
+
+ def hdrlcxt
+ "\xf0\x00\x00\x66\x11"
+ end
+end
diff --git a/libs/surfaces/mackie/scripts/parse.rb b/libs/surfaces/mackie/scripts/parse.rb
new file mode 100644
index 0000000000..3a225a5756
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/parse.rb
@@ -0,0 +1,61 @@
+#! /usr/bin/ruby
+# Copyright (C) 2006,2007 John Anderson
+
+# 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.
+
+require "rexml/document"
+file = File.new( ARGV[0] )
+doc = REXML::Document.new file
+
+# fetch the node containing the controls
+controls = XPath.first( doc, 'Session/ControlProtocols/Protocol[@name="Generic MIDI"]/controls' )
+
+channel = 1
+
+# A Control is a button or slider. It has an internal ID
+# an incoming MIDI message, and an outgoing midi message
+class Control
+
+end
+
+# Strips have solo,rec,mute,pan,fader
+# Strips have midi input
+# Strips have midi output
+# Strips have an XML representation, or something like that
+class Strip
+ def initialize( node )
+ @solo = node.elements['solo']
+ @mute = node.elements['mute']
+ @rec = node.elements['recenable']
+ @fader = node.elements['IO/gaincontrol']
+ @panner = node.elements['IO/Panner/StreamPanner/panner']
+ end
+end
+
+# This knows how to extract a set of controls from a Route
+
+doc.elements.each( 'Session/Routes/Route' ) do |node|
+ strip = Strip.new( node )
+
+ controls.add_element( 'mute',
+ 'id' => mute.attribute('id').value,
+ 'event' => "0xb0",
+ 'channel' => channel.to_s,
+ 'additional' => "0x41"
+ )
+
+end
+
+pp controls.elements
diff --git a/libs/surfaces/mackie/scripts/signals.rb b/libs/surfaces/mackie/scripts/signals.rb
new file mode 100644
index 0000000000..8182e562a3
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/signals.rb
@@ -0,0 +1,137 @@
+#~ /usr/bin/ruby
+# Copyright (C) 2006,2007 John Anderson
+
+# 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.
+
+require 'erb'
+
+signals = %w{
+solo_changed
+mute_changed
+record_enable_changed
+gain_changed
+name_changed
+panner_changed
+}
+
+@signal_calls = { 'panner_changed' => 'panner()[0]->Changed' }
+
+def connection_call( x )
+ if @signal_calls.include? x
+ @signal_calls[x]
+ else
+ x
+ end
+end
+
+signals.each do |x|
+ puts <<EOF
+void MackieControlProtocol::notify_#{x}( void *, ARDOUR::Route * route )
+{
+ try
+ {
+ strip_from_route( route ).#{x.gsub( /_changed/, '' )}();
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+EOF
+end
+
+class_def = <<EOF
+#ifndef route_signal_h
+#define route_signal_h
+
+#include <sigc++/sigc++.h>
+
+class MackieControlProtocol;
+
+namespace ARDOUR {
+ class Route;
+}
+
+namespace Mackie
+{
+
+class Strip;
+
+/**
+ This class is intended to easily create and destroy the set of
+ connections from a route to a control surface strip. Instanting
+ it will connect the signals, and destructing it will disconnect
+ the signals.
+*/
+class RouteSignal
+{
+public:
+ RouteSignal( ARDOUR::Route & route, MackieControlProtocol & mcp, Strip & strip )
+ : _route( route ), _mcp( mcp ), _strip( strip )
+ {
+ connect();
+ }
+
+ ~RouteSignal()
+ {
+ disconnect();
+ }
+
+private:
+ ARDOUR::Route & _route;
+ MackieControlProtocol & _mcp;
+ Strip & _strip;
+
+<% signals.each do |x| -%>
+ sigc::connection _<%= x %>_connection;
+<% end -%>
+};
+
+}
+
+#endif
+EOF
+
+erb = ERB.new( class_def, 0, ">-" )
+erb.run
+
+impl_def = <<EOF
+#include "route_signal.h"
+
+#include <ardour/route.h>
+#include <ardour/panner.h>
+
+#include "mackie_control_protocol.h"
+
+using namespace Mackie;
+
+void RouteSignal::connect()
+{
+<% signals.each do |x| -%>
+ _<%=x%>_connection = _route.<%=connection_call(x)%>.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_<%=x%> ), &_route ) );
+<% end -%>
+}
+
+void RouteSignal::disconnect()
+{
+<% signals.each do |x| -%>
+ _<%= x %>_connection.disconnect();
+<% end -%>
+}
+EOF
+
+erb = ERB.new( impl_def, 0, ">-" )
+erb.run
diff --git a/libs/surfaces/mackie/scripts/simple_host.rb b/libs/surfaces/mackie/scripts/simple_host.rb
new file mode 100644
index 0000000000..a5c07f2abb
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/simple_host.rb
@@ -0,0 +1,137 @@
+#! /usr/bin/ruby
+# Copyright (C) 2006,2007 John Anderson
+
+# 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.
+
+require 'mackie'
+
+buttons = {}
+pots = {}
+
+while !File.exist? ARGV[0]
+ sleep 0.010
+end
+
+file = File.open( ARGV[0], 'r+' )
+mck = Mackie.new( file )
+
+# faders to minimum. bcf2000 doesn't respond
+mck.write_sysex "\x61"
+
+# all leds off. bcf2000 doesn't respond
+mck.write_sysex "\x62"
+
+# get version. comes back as ASCII bytes
+version = mck.sysex "\x13\x00"
+puts "version: #{version.map{|x| x.chr}}"
+
+# respond to control movements
+while bytes = file.read( 3 )
+ puts "received: %02.x %02.x %02.x" % [ bytes[0], bytes[1], bytes[2] ]
+ output = nil
+ case bytes[0] & 0b11110000
+ when 0xe0
+ # fader moved, so respond if move is OK
+ output = bytes
+ when 0x90
+ # button pressed
+ case bytes[1]
+ when 0x68..0x6f
+ # do nothing - touch detection
+ puts "touch detect: %02.x" % bytes[2]
+ else
+ # treat all buttons as toggles
+ button_id = bytes[1]
+
+ # only toggle on release. Not working. All buttons send press
+ # and then release signals
+ if bytes[2] == 0
+ if buttons.include?( button_id )
+ # toggle button state
+ puts "button id #{buttons[button_id]} to #{!buttons[button_id]}"
+ buttons[button_id] = !buttons[button_id]
+ else
+ # create a new button as on
+ puts "adding button id #{button_id}"
+ buttons[button_id] = true
+ end
+ bytes[2] = buttons[button_id] ? 0x7f : 0
+ output = bytes
+ end
+ end
+ when 0xb0
+ # pots, jog wheel, external
+ case bytes[1]
+ when 0x10..0x17
+ #pot turned
+ pot_id = bytes[1] & 0b00000111
+ direction = bytes[2] & 0b01000000
+ delta = bytes[2] & 0b00111111
+ sign = direction == 0 ? 1 : -1
+
+ if pots.include? pot_id
+ current_led_pos = pots[pot_id]
+ else
+ current_led_pos = pots[pot_id] = 6
+ end
+ new_led_pos = current_led_pos + sign
+ new_led_pos = case
+ when new_led_pos <= 0
+ 0
+ when new_led_pos >= 11
+ 11
+ else
+ new_led_pos
+ end
+
+ pots[pot_id] = new_led_pos
+
+ puts "pot #{pot_id} turned #{sign} #{direction == 0 ? 'clockwise' : 'widdershins'}: %02.x to #{new_led_pos}" % delta
+
+ output = bytes
+ output[1] += 0x20
+ output[2] = 0b01000000
+ #~ modes:
+ #~ 0 - single dot
+ #~ 1 - boost/cut
+ #~ 2 - wrap
+ #~ 3 - spread
+ mode = pot_id < 4 ? pot_id : 0
+ output[2] |= ( mode << 4 )
+ output[2] += ( new_led_pos ) & 0b00001111
+ when 0x2e
+ # external controller
+ when 0x3c
+ # jog wheel
+ end
+ else
+ puts "don't know what this means"
+ end
+
+ # output bytes
+ if output
+ #sleep 0.1
+ puts "sending: %02.x %02.x %02.x" % [ output[0], output[1], output[2] ]
+ begin
+ res = file.write output
+ puts "res: #{res}"
+ file.flush
+ rescue => e
+ puts "oops #{e}"
+ file.close
+ file = File.open ARGV[0], 'r+'
+ end
+ end
+end
diff --git a/libs/surfaces/mackie/scripts/surface-cc-template.erb b/libs/surfaces/mackie/scripts/surface-cc-template.erb
new file mode 100644
index 0000000000..3b29be3249
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/surface-cc-template.erb
@@ -0,0 +1,95 @@
+<%#
+ Copyright (C) 2006,2007 John Anderson
+
+ 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.
+-%>
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "<%= sf.name.downcase %>_surface.h"
+
+#include "controls.h"
+#include "mackie_button_handler.h"
+
+using namespace Mackie;
+
+void Mackie::<%= sf.name %>Surface::init_controls()
+{
+ // intialise groups and strips
+ Group * group = 0;
+
+ // make sure there are enough strips
+ strips.resize( <%= sf.groups.values.find_all{|x| x.name =~ /strip/}.size %> );
+
+% sf.groups.values.each do |group|
+ <%- if group.class == Strip -%>
+ <%- if group.name == 'master' -%>
+ group = new MasterStrip ( "<%=group.name%>", 0 );
+ <%- else -%>
+ group = new <%= group.class.name %> ( "<%=group.name%>", <%=group.ordinal - 1%> );
+ <%- end -%>
+ <%- else -%>
+ group = new <%= group.class.name %> ( "<%=group.name%>" );
+ <%- end -%>
+ groups["<%=group.name%>"] = group;
+ <%- if group.class == Strip -%>
+ strips[<%=group.ordinal - 1%>] = dynamic_cast<Strip*>( group );
+ <%- end -%>
+
+% end
+
+ // initialise controls
+ Control * control = 0;
+
+% sf.controls.each do |control|
+ group = groups["<%=control.group.name%>"];
+ control = new <%= control.class.name %> ( <%= control.id %>, <%= control.ordinal %>, "<%=control.name%>", *group );
+ <%=control.class.name.downcase%>s[0x<%=control.id.to_hex %>] = control;
+ controls.push_back( control );
+ <%- if control.group.class != Strip -%>
+ controls_by_name["<%= control.name %>"] = control;
+ <%- end -%>
+ group->add( *control );
+
+% end
+}
+
+void Mackie::<%= sf.name %>Surface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
+{
+ if ( bs != press && bs != release )
+ {
+ mbh.update_led( button, none );
+ return;
+ }
+
+ LedState ls;
+ switch ( button.id() )
+ {
+<%-
+buttons = sf.controls.find_all{|x| x.class == Button && x.group.class != Strip}
+buttons.each do |button|
+%>
+ case 0x<%= button.id.to_hex %>: // <%= button.name %>
+ switch ( bs ) {
+ case press: ls = mbh.<%= button.name %>_press( button ); break;
+ case release: ls = mbh.<%= button.name %>_release( button ); break;
+ case neither: break;
+ }
+ break;
+<% end %>
+ }
+ mbh.update_led( button, ls );
+}
diff --git a/libs/surfaces/mackie/scripts/surface-h-template.erb b/libs/surfaces/mackie/scripts/surface-h-template.erb
new file mode 100644
index 0000000000..2f54f66c47
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/surface-h-template.erb
@@ -0,0 +1,27 @@
+#ifndef mackie_surface_<%= sf.name.downcase %>_h
+#define mackie_surface_<%= sf.name.downcase %>_h
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "surface.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler;
+
+class <%= sf.name %>Surface : public Surface
+{
+public:
+ <%= sf.name %>Surface( uint32_t max_strips ) : Surface( max_strips )
+ {
+ }
+
+ virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
+ virtual void init_controls();
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/scripts/test_controls.rb b/libs/surfaces/mackie/scripts/test_controls.rb
new file mode 100755
index 0000000000..782b0d427c
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/test_controls.rb
@@ -0,0 +1,9 @@
+#! /usr/bin/ruby
+
+require 'controls.rb'
+require 'pp'
+
+sf = Surface.new
+sf.parse
+sf.types.each{|k,v| puts "%02.x #{v}" % k}
+
diff --git a/libs/surfaces/mackie/scripts/transform.rb b/libs/surfaces/mackie/scripts/transform.rb
new file mode 100644
index 0000000000..e0221e188b
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/transform.rb
@@ -0,0 +1,26 @@
+class ElementHandler
+
+ def apply( anElement )
+ anElement.each {|e| handle(e)} if anElement
+ end
+
+ def handle( aNode )
+ if aNode.kind_of? REXML::Text
+ handleTextNode(aNode)
+ elsif aNode.kind_of? REXML::Element
+ handle_element aNode
+ else
+ return #ignore comments and processing instructions
+ end
+ end
+
+ def handle_element( anElement )
+ handler_method = "handle_" + anElement.name.tr("-","_")
+ if self.respond_to? handler_method
+ self.send(handler_method, anElement)
+ else
+ default_handler(anElement)
+ end
+ end
+
+end
diff --git a/libs/surfaces/mackie/scripts/write.rb b/libs/surfaces/mackie/scripts/write.rb
new file mode 100644
index 0000000000..20b72477e8
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/write.rb
@@ -0,0 +1,10 @@
+#! /usr/bin/ruby
+
+require 'mackie.rb'
+
+@file = File.open '/dev/snd/midiC2D0', 'r+'
+
+@led_8_on = [ 0x90, 0x18, 0x7f ]
+@hci = [ 0, 0xf7 ]
+@version_req = [ 0x13, 0, 0xf7 ]
+
diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc
new file mode 100644
index 0000000000..01be2c60c2
--- /dev/null
+++ b/libs/surfaces/mackie/surface.cc
@@ -0,0 +1,142 @@
+#include "surface.h"
+
+#include <sstream>
+#include <iomanip>
+#include <iostream>
+
+using namespace std;
+using namespace Mackie;
+
+Surface::Surface( uint32_t max_strips, uint32_t unit_strips )
+: _max_strips( max_strips ), _unit_strips( unit_strips )
+{
+}
+
+void Surface::init()
+{
+ init_controls();
+ init_strips( _max_strips, _unit_strips );
+}
+
+Surface::~Surface()
+{
+ // delete groups
+ for( Groups::iterator it = groups.begin(); it != groups.end(); ++it )
+ {
+ delete it->second;
+ }
+
+ // delete controls
+ for( Controls::iterator it = controls.begin(); it != controls.end(); ++it )
+ {
+ delete *it;
+ }
+}
+
+// Mackie-specific, because of multiple devices on separate ports
+// add the strips from 9..max_strips
+// unit_strips is the number of strips for additional units.
+void Surface::init_strips( uint32_t max_strips, uint32_t unit_strips )
+{
+ if ( strips.size() < max_strips )
+ {
+ strips.resize( max_strips );
+ for ( uint32_t i = strips.size(); i < max_strips; ++i )
+ {
+ // because I can't find itoa
+ ostringstream os;
+ os << "strip_" << i + 1;
+ string name = os.str();
+
+ // shallow copy existing strip
+ // which works because the controls
+ // have the same ids across units
+ Strip * strip = new Strip( *strips[i % unit_strips] );
+
+ // update the relevant values
+ strip->index( i );
+ strip->name( name );
+
+ // add to data structures
+ groups[name] = strip;
+ strips[i] = strip;
+ }
+ }
+}
+
+ostream & Mackie::operator << ( ostream & os, const Mackie::Control & control )
+{
+ os << typeid( control ).name();
+ os << " { ";
+ os << "name: " << control.name();
+ os << ", ";
+ os << "id: " << "0x" << setw(2) << setfill('0') << hex << control.id() << setfill(' ');
+ os << ", ";
+ os << "ordinal: " << dec << control.ordinal();
+ os << ", ";
+ os << "group: " << control.group().name();
+ os << " }";
+
+ return os;
+}
+
+/**
+ TODO could optimise this to use enum, but it's only
+ called during the protocol class instantiation.
+
+ generated using
+
+ irb -r controls.rb
+ sf=Surface.new
+ sf.parse
+ controls = sf.groups.find{|x| x[0] =~ /strip/}.each{|x| puts x[1]}
+ controls[1].each {|x| puts "\telse if ( control.name() == \"#{x.name}\" )\n\t{\n\t\t_#{x.name} = reinterpret_cast<#{x.class.name}*>(&control);\n\t}\n"}
+*/
+void Strip::add( Control & control )
+{
+ Group::add( control );
+ if ( control.name() == "gain" )
+ {
+ _gain = reinterpret_cast<Fader*>(&control);
+ }
+ else if ( control.name() == "vpot" )
+ {
+ _vpot = reinterpret_cast<Pot*>(&control);
+ }
+ else if ( control.name() == "recenable" )
+ {
+ _recenable = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "solo" )
+ {
+ _solo = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "mute" )
+ {
+ _mute = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "select" )
+ {
+ _select = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "vselect" )
+ {
+ _vselect = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "fader_touch" )
+ {
+ _fader_touch = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.type() == Control::type_led || control.type() == Control::type_led_ring )
+ {
+ // do nothing
+ cout << "Strip::add not adding " << control << endl;
+ }
+ else
+ {
+ ostringstream os;
+ os << "Strip::add: unknown control type " << control;
+ throw MackieControlException( os.str() );
+ }
+}
+
diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h
new file mode 100644
index 0000000000..0ccde75537
--- /dev/null
+++ b/libs/surfaces/mackie/surface.h
@@ -0,0 +1,94 @@
+#ifndef mackie_surface_h
+#define mackie_surface_h
+
+#include "controls.h"
+#include "types.h"
+#include <stdint.h>
+
+namespace Mackie
+{
+
+class MackieButtonHandler;
+
+/**
+ This represents an entire control surface, made up of Groups,
+ Strips and Controls. There are several collections for
+ ease of addressing in different ways, but only one collection
+ has definitive ownership.
+
+ It handles mapping button ids to press_ and release_ calls.
+
+ There are various emulations of the Mackie around, so specific
+ emulations will inherit from this to change button mapping, or
+ have 7 fader channels instead of 8, or whatever.
+
+ Currently there are BcfSurface and MackieSurface.
+
+ TODO maybe make Group inherit from Control, for ease of ownership.
+*/
+class Surface
+{
+public:
+ /**
+ A Surface can be made up of multiple units. eg one Mackie MCU plus
+ one or more Mackie MCU extenders.
+
+ \param max_strips is the number of strips for the entire surface.
+ \param unit_strips is the number of strips per unit.
+ */
+ Surface( uint32_t max_strips, uint32_t unit_strips = 8 );
+ virtual ~Surface();
+
+ /// Calls the virtual initialisation methods. This *must* be called after
+ /// construction, because c++ is too dumb to call virtual methods from
+ /// inside a constructor
+ void init();
+
+ typedef std::vector<Control*> Controls;
+
+ /// This collection has ownership of all the controls
+ Controls controls;
+
+ /**
+ These are alternative addressing schemes
+ They use maps because the indices aren't always
+ 0-based.
+ */
+ std::map<int,Control*> faders;
+ std::map<int,Control*> pots;
+ std::map<int,Control*> buttons;
+ std::map<int,Control*> leds;
+
+ /// no strip controls in here because they usually
+ /// have the same names.
+ std::map<std::string,Control*> controls_by_name;
+
+ /// The collection of all numbered strips. No master
+ /// strip in here.
+ typedef std::vector<Strip*> Strips;
+ Strips strips;
+
+ /// This collection owns the groups
+ typedef std::map<std::string,Group*> Groups;
+ Groups groups;
+
+ uint32_t max_strips() const
+ {
+ return _max_strips;
+ }
+
+ /// map button ids to calls to press_ and release_ in mbh
+ virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button ) = 0;
+
+protected:
+ virtual void init_controls() = 0;
+ virtual void init_strips( uint32_t max_strips, uint32_t unit_strips );
+
+private:
+ uint32_t _max_strips;
+ uint32_t _unit_strips;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc
new file mode 100644
index 0000000000..8aa1be7fe9
--- /dev/null
+++ b/libs/surfaces/mackie/surface_port.cc
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 "surface_port.h"
+
+#include "mackie_control_exception.h"
+#include "controls.h"
+
+#include <midi++/types.h>
+#include <midi++/port.h>
+#include <sigc++/sigc++.h>
+#include <boost/shared_array.hpp>
+
+#include "i18n.h"
+
+#include <sstream>
+
+#include <cstring>
+#include <cerrno>
+
+using namespace std;
+using namespace Mackie;
+
+SurfacePort::SurfacePort( MIDI::Port & port, int number )
+: _port( port ), _number( number ), _active( false )
+{
+}
+
+SurfacePort::~SurfacePort()
+{
+ //cout << "~SurfacePort::SurfacePort()" << endl;
+ // make sure another thread isn't reading or writing as we close the port
+ Glib::RecMutex::Lock lock( _rwlock );
+ _active = false;
+ //cout << "~SurfacePort::SurfacePort() finished" << endl;
+}
+
+// wrapper for one day when strerror_r is working properly
+string fetch_errmsg( int error_number )
+{
+ char * msg = strerror( error_number );
+ return msg;
+}
+
+MidiByteArray SurfacePort::read()
+{
+ const int max_buf_size = 512;
+ MIDI::byte buf[max_buf_size];
+ MidiByteArray retval;
+
+ // check active. Mainly so that the destructor
+ // doesn't destroy the mutex while it's still locked
+ if ( !active() ) return retval;
+
+ // return nothing read if the lock isn't acquired
+ Glib::RecMutex::Lock lock( _rwlock, Glib::TRY_LOCK );
+
+ if ( !lock.locked() )
+ {
+ //cout << "SurfacePort::read not locked" << endl;
+ return retval;
+ }
+
+ // check active again - destructor sequence
+ if ( !active() ) return retval;
+
+ // read port and copy to return value
+ int nread = port().read( buf, sizeof (buf), 0 );
+
+ if (nread >= 0) {
+ retval.copy( nread, buf );
+ if ((size_t) nread == sizeof (buf))
+ {
+ retval << read();
+ }
+ }
+ else
+ {
+ if ( errno != EAGAIN )
+ {
+ ostringstream os;
+ os << "Surface: error reading from port: " << port().name();
+ os << ": " << errno << fetch_errmsg( errno );
+
+ cout << os.str() << endl;
+ inactive_event();
+ throw MackieControlException( os.str() );
+ }
+ }
+ return retval;
+}
+
+void SurfacePort::write( const MidiByteArray & mba )
+{
+ //if ( mba[0] == 0xf0 ) cout << "SurfacePort::write: " << mba << endl;
+ //cout << "SurfacePort::write: " << mba << endl;
+
+ // check active before and after lock - to make sure
+ // that the destructor doesn't destroy the mutex while
+ // it's still in use
+ if ( !active() ) return;
+ Glib::RecMutex::Lock lock( _rwlock );
+ if ( !active() ) return;
+
+ int count = port().write( mba.bytes().get(), mba.size(), 0 );
+ if ( count != (int)mba.size() )
+ {
+ if ( errno != EAGAIN )
+ {
+ ostringstream os;
+ os << "Surface: couldn't write to port " << port().name();
+ os << ": " << errno << fetch_errmsg( errno );
+
+ cout << os.str();
+ inactive_event();
+ throw MackieControlException( os.str() );
+ }
+ }
+ //if ( mba[0] == 0xf0 ) cout << "SurfacePort::write " << count << endl;
+}
+
+void SurfacePort::write_sysex( const MidiByteArray & mba )
+{
+ MidiByteArray buf;
+ buf << sysex_hdr() << mba << MIDI::eox;
+ write( buf );
+}
+
+void SurfacePort::write_sysex( MIDI::byte msg )
+{
+ MidiByteArray buf;
+ buf << sysex_hdr() << msg << MIDI::eox;
+ write( buf );
+}
+
+// This should be moved to midi++ at some point
+ostream & operator << ( ostream & os, const MIDI::Port & port )
+{
+ os << "device: " << port.device();
+ os << "; ";
+ os << "name: " << port.name();
+ os << "; ";
+ os << "type: " << port.type();
+ os << "; ";
+ os << "mode: " << port.mode();
+ os << "; ";
+ os << "ok: " << port.ok();
+ os << "; ";
+ os << "number: " << port.number();
+ os << "; ";
+ return os;
+}
+
+ostream & Mackie::operator << ( ostream & os, const SurfacePort & port )
+{
+ os << "{ ";
+ os << "device: " << port.port().device();
+ os << "; ";
+ os << "name: " << port.port().name();
+ os << "; ";
+ os << "number: " << port.number();
+ os << " }";
+ return os;
+}
diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h
new file mode 100644
index 0000000000..87419f1bcd
--- /dev/null
+++ b/libs/surfaces/mackie/surface_port.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 surface_port_h
+#define surface_port_h
+
+#include <sigc++/signal.h>
+#include <glibmm/thread.h>
+
+#include "midi_byte_array.h"
+#include "types.h"
+
+namespace MIDI {
+ class Port;
+}
+
+namespace Mackie
+{
+
+/**
+ Make a relationship between a midi port and a Mackie device.
+*/
+class SurfacePort : public sigc::trackable
+{
+public:
+ SurfacePort( MIDI::Port & port, int number );
+ virtual ~SurfacePort();
+
+ // when this is successful, active() should return true
+ virtual void open() = 0;
+
+ // subclasses should call this before doing their own close
+ virtual void close() = 0;
+
+ /// read bytes from the port. They'll either end up in the
+ /// parser, or if that's not active they'll be returned
+ MidiByteArray read();
+
+ /// an easier way to output bytes via midi
+ void write( const MidiByteArray & );
+
+ /// write a sysex message
+ void write_sysex( const MidiByteArray & mba );
+ void write_sysex( MIDI::byte msg );
+
+ // return the correct sysex header for this port
+ virtual const MidiByteArray & sysex_hdr() const = 0;
+
+ MIDI::Port & port() { return _port; }
+ const MIDI::Port & port() const { return _port; }
+
+ // all control notofications are sent from here
+ sigc::signal<void, SurfacePort &, Control &, const ControlState &> control_event;
+
+ // emitted just before the port goes into initialisation
+ // where it tries to establish that its device is connected
+ sigc::signal<void> init_event;
+
+ // emitted when the port completes initialisation successfully
+ sigc::signal<void> active_event;
+
+ // emitted when the port goes inactive (ie a read or write failed)
+ sigc::signal<void> inactive_event;
+
+ // the port number - master is 0, extenders are 1,2,3,4
+ virtual int number() const { return _number; }
+
+ // number of strips handled by this port. Usually 8.
+ virtual int strips() const = 0;
+
+ virtual bool active() const { return _active; }
+ virtual void active( bool yn ) { _active = yn; }
+
+private:
+ MIDI::Port & _port;
+ int _number;
+ bool _active;
+
+ Glib::RecMutex _rwlock;
+};
+
+std::ostream & operator << ( std::ostream & , const SurfacePort & port );
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/test.cc b/libs/surfaces/mackie/test.cc
new file mode 100644
index 0000000000..351058523f
--- /dev/null
+++ b/libs/surfaces/mackie/test.cc
@@ -0,0 +1,25 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <cstdarg>
+#include <iomanip>
+
+#include "midi_byte_array.h"
+
+using namespace std;
+
+namespace MIDI {
+ typedef unsigned char byte;
+ byte sysex = 0xf0;
+ byte eox = 0xf7;
+}
+
+int main()
+{
+ MidiByteArray bytes( 4, 0xf0, 0x01, 0x03, 0x7f );
+ cout << bytes << endl;
+ return 0;
+}
+
diff --git a/libs/surfaces/mackie/types.cc b/libs/surfaces/mackie/types.cc
new file mode 100644
index 0000000000..d2818d7340
--- /dev/null
+++ b/libs/surfaces/mackie/types.cc
@@ -0,0 +1,9 @@
+#include "types.h"
+
+namespace Mackie
+{
+ LedState on( LedState::on );
+ LedState off( LedState::off );
+ LedState flashing( LedState::flashing );
+ LedState none( LedState::none );
+}
diff --git a/libs/surfaces/mackie/types.h b/libs/surfaces/mackie/types.h
new file mode 100644
index 0000000000..2b47e15640
--- /dev/null
+++ b/libs/surfaces/mackie/types.h
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 mackie_types_h
+#define mackie_types_h
+
+namespace Mackie
+{
+
+/**
+ This started off as an enum, but it got really annoying
+ typing ? on : off
+*/
+class LedState
+{
+public:
+ enum state_t { none, off, flashing, on };
+ LedState() : _state( none ) {}
+ LedState( bool yn ): _state( yn ? on : off ) {}
+ LedState( state_t state ): _state( state ) {}
+
+ bool operator == ( const LedState & other ) const
+ {
+ return state() == other.state();
+ }
+
+ bool operator != ( const LedState & other ) const
+ {
+ return state() != other.state();
+ }
+
+ state_t state() const { return _state; }
+
+private:
+ state_t _state;
+};
+
+extern LedState on;
+extern LedState off;
+extern LedState flashing;
+extern LedState none;
+
+enum ButtonState { neither = -1, release = 0, press = 1 };
+
+/**
+ Contains the state for a control, with some convenience
+ constructors
+*/
+struct ControlState
+{
+ ControlState(): pos(0.0), delta(0.0), button_state(neither) {}
+
+ ControlState( LedState ls ): pos(0.0), delta(0.0), led_state(ls), button_state(neither) {}
+
+ // Note that this sets both pos and delta to the flt value
+ ControlState( LedState ls, float flt ): pos(flt), delta(flt), ticks(0), led_state(ls), button_state(neither) {}
+ ControlState( float flt ): pos(flt), delta(flt), ticks(0), led_state(none), button_state(neither) {}
+ ControlState( float flt, int tcks ): pos(flt), delta(flt), ticks(tcks), led_state(none), button_state(neither) {}
+ ControlState( ButtonState bs ): pos(0.0), delta(0.0), ticks(0), led_state(none), button_state(bs) {}
+
+ float pos;
+ float delta;
+ int ticks;
+ LedState led_state;
+ ButtonState button_state;
+};
+
+class Control;
+class Fader;
+class Button;
+class Strip;
+class Group;
+class Pot;
+class Led;
+class LedRing;
+
+}
+
+#endif
diff --git a/libs/surfaces/tranzport/README b/libs/surfaces/tranzport/README
new file mode 100644
index 0000000000..e2d37c84bf
--- /dev/null
+++ b/libs/surfaces/tranzport/README
@@ -0,0 +1,90 @@
+
+I'm putting this here because I don't really have a place to put it, unless I create a web page and have a place to keep the code.
+
+While doing some exaustive testing of my latest code (read - playing a ton of music) I have done some thinking about the ui, and decided that under apparent simplicity should lie complexity.
+
+The "flash" screen idea I am going to drop, and replace it with the idea of a notify area being declared on each screen.
+
+When the unit is idle, these messages will appear in that area statically. When the transport is running, these messages will still appear in that space, which is usually where the meter is. It's actually possible to rapidly flash the area between the competing writers and get a nifty faded effect. (I came across this idea accidentally when I had a pointer overrun)
+
+Also certain things will update on top of each other, whatever was updated
+last will stay on the screen. This is Pan/Gain primarily.
+
+I need a way to get messages back into the tranzport. Example - I hit Undo, what was undone? Redo, same problem.
+
+I've already found many uses for being able to control more than 1 track at a time, so I think that although I'm *usually* controlling one track at a time, being able to quickly access all tracks would be good.
+
+Example - want to have meters for all tracks running and be able to control the
+db/pan settings of the track I'm on....
+
+What I am going to go with is multifold - but first my design goal: I want to do everything required for a solo musician wielding an instrument to NOT have to touch a keyboard or look at a big screen. When you are wrapped behind a bass, it's difficult to cope with that - but the tranzport is a great alternative.
+
+Most screens will have *4* items on them.
+
+There will be "display views" - which are more informational and bling oriented.
+
+There will be "Track based views"- which basically do track specific things
+
+There will be "interactive views",which basically allow for more input than output. They will do something to highlight the current selection.
+Scroll wheel will select between values for a field. Track Next/Prev will move between fields. I would like to have a "No/Yes" option (hit record for yes? Stop for no?) but I'm still a little vague on that.
+
+Things to do:
+
+A) Hitting "Shift->Spacebar" will switch "views". There are ultimately going to be dozens of views. At present, there are only the "Normal" and "Big Meter" views.
+
+Each view will change somewhat based on the state of the transport. Holding down shift for a second will switch to the "underlying display"....
+
+Here's how the "normal" view looks today in my tree:
+
+VIEW: NORMAL
+
+Play Mode: Stopped
+[Trackname[16]] [gain/pan[4]]
+[Modes[9]] long smpte/bar counter]
+
+Play Mode: Playing > 1.0 speed
+[Trackname[16]] [gain/pan[4]]
+[meter[16]] short smpte/bar counter]
+
+Play Mode: Playing < 1.0
+[Trackname[16]] [gain/pan[4]]
+[meter[9]] long smpte/bar counter]
+
+Play Mode: Recording
+[Trackname[16]] [gain/pan[4]]
+[meter[16]] short smpte/bar counter]
+
+Other views (in order of development priority)
+
+Marker Mode: Edit markers, setup loops and punch in points.
+Config Mode: Load/Save settings, Load/Save project. Set wheel SnapTo
+Loop Mode: Show track, raise layers to top for playback, editing, deletion, loop on and off, etc
+
+It's possible that config mode will have a "MORE" field, or ways to move around the configuration (ffw/Play?)
+
+(the first two are the two modes I most need personally. If you have a suggestion...)
+
+Mastering Mode - display master and current track with meters and panner/db
+Automation Mode - I really don't think I have the pixels for this
+
+(I've already abstracted out the code to do most of these, but it's bling, I'm not going to bother much with it soon)
+
+Quad Meter Mode
+Inverted Meter mode (draws meters backwards)
+Quad Inverted Meter mode (bling, but my car stereo has it, and it's cool)
+10 8 bar meter mode
+5 8 bar meter mode
+
+I haven't written the panner yet, doing the stereo meter killed me.
+
+From a development perspective I'm going to keep revising the code to make it more stable and merely tie the new mode modes to the "bling mode"s until they are ready for prime time. I should be able to put out releases once a week for a while.
+
+A big help would be moving these items into a higher level of abstraction (revising the baseUI class).
+
+In particular, I'd really like "slave" mode. Snapto increment is really important....
+
+Here's an example of something that should be fairly easy to export to the Base::UI subclasses - the current state of the main keyboard's shift key.
+
+That way, when shift is held down for a few seconds on the regular keyboard, I can see what's underneath the current tranzport display mode (I do like big meters) (Also, it's somewhat easier to hit shift on the main keyboard and play on the tranzport or the shuttle wheel, if that's what you are doing).
+
+Should be fairly easy to tap into the gdk event for this but the "right way" to propagate this event into the class is beyond me.
diff --git a/libs/surfaces/tranzport/SConscript b/libs/surfaces/tranzport/SConscript
index 5d390f3e2f..a154685299 100644
--- a/libs/surfaces/tranzport/SConscript
+++ b/libs/surfaces/tranzport/SConscript
@@ -22,13 +22,36 @@ tranzport.Append(POTFILE = domain + '.pot')
tranzport_files=Split("""
interface.cc
-tranzport_control_protocol.cc
+buttons.cc
+io.cc
+io_usb.cc
+panner.cc
+lights.cc
+screen.cc
+state.cc
+wheel_modes.cc
+button_events.cc
+general.cc
+lcd.cc
+mode.cc
+show.cc
+init.cc
+wheel.cc
""")
+#figure out when to do
+#io_usb.cc
+#io_midi.cc
+#io_kernel.cc
+
tranzport.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
tranzport.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
tranzport.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
tranzport.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+#if env['HAVE_TRANZPORT_KERNEL_DRIVER']:
+# tranzport.Append(CXXFLAGS="-DHAVE_TRANZPORT_KERNEL_DRIVER=1")
+
+#merge more into tranzport files for the right io lib
tranzport.Merge ([
libraries['ardour'],
@@ -37,20 +60,23 @@ tranzport.Merge ([
libraries['pbd'],
libraries['midi++2'],
libraries['xml'],
- libraries['usb'],
libraries['glib2'],
- libraries['glibmm2']
+ libraries['glibmm2'],
+ libraries['usb'],
+ libraries['sndfile-ardour']
])
libardour_tranzport = tranzport.SharedLibrary('ardour_tranzport', tranzport_files)
if tranzport['TRANZPORT']:
- Default(libardour_tranzport)
- if env['NLS']:
- i18n (tranzport, tranzport_files, env)
- env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_tranzport))
+ Default(libardour_tranzport)
+ if env['NLS']:
+ i18n (tranzport, tranzport_files, env)
+# if env['HAVE_TRANZPORT_KERNEL_DRIVER']:
+# tranzport.Merge([ libraries['usb'] ])
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_tranzport))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
- [ 'SConscript' ] +
- tranzport_files +
- glob.glob('po/*.po') + glob.glob('*.h')))
+ [ 'SConscript' ] +
+ tranzport_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/tranzport/TODO b/libs/surfaces/tranzport/TODO
new file mode 100644
index 0000000000..216a5bc9d0
--- /dev/null
+++ b/libs/surfaces/tranzport/TODO
@@ -0,0 +1,6 @@
+BREAK APART DRIVER INTO SIMPLER CHUNKS - done
+GET KERNEL DRIVER WORKING
+GET TRIPLE THREADED DRIVER WORKING
+STABLIZE THE API
+ADOPT SOME CONVENTIONS FROM THE MACKIE
+GET SAVING STATE WORKING
diff --git a/libs/surfaces/tranzport/bling.cc b/libs/surfaces/tranzport/bling.cc
new file mode 100644
index 0000000000..c60b699f3d
--- /dev/null
+++ b/libs/surfaces/tranzport/bling.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* The Bling class theoretically knows nothing about the device it's blinging
+ and depends on the overlying implementation to tell it about the format of the
+ device. Maybe this will become a template or people will inherit from it */
+
+/* Bling is where all the bad, bad, marketing driven ideas go */
+
+class bling {
+public:
+ enum BlingMode {
+ BlingOff = 0,
+ BlingOn = 1,
+ BlingEnter = 2,
+ BlingExit = 4,
+ // Light Specific Stuff
+ BlingKit = 8,
+ BlingRotating = 16,
+ BlingPairs = 32,
+ BlingRows = 64,
+ BlingColumns = 128,
+ BlingFlashAllLights = 256,
+ // Screen Specific Stuff
+ // Slider Specific Stuff
+ BlingSliderMax,
+ BlingSliderMid,
+ BlingSliderMin,
+ // Random stuff
+ BlingRandomLight,
+ BlingRandomSlider,
+ BlingRandomScreen,
+ BlingAllSliders
+ };
+ bling();
+ ~bling();
+ set(BlingMode);
+ unset(BlingMode);
+ run();
+ next();
+ prev();
+ msg(string&);
+ scrollmsg(string&);
+
+protected:
+// The as yet undefined "advanced_ui" class provides methods to find out at run time
+// what the heck is what
+ BlingMode blingmode;
+ advancedUI *intf;
+ int last_light;
+// I don't think these actually need to be part of the public definition of the class
+ enter();
+ exit();
+ rotate();
+// etc
+};
+
+// make absolutely sure we have the pointer to the interface
+// something like this
+
+#define BLING_INTFA(a) (intf)? 0:intf->a
+#define BLING_INTF(a) { if (intf) { intf->a; } else { return 0; } }
+
+// Should any of these bother to return a status code?
+
+bling::rotate() {
+ BLING_INTF(light(last_light,off));
+ last_light = BLING_INTFA(next_light(last_light));
+ BLING_INTF(light(last_light,on));
+}
+
+bling::enter() {
+}
+
+bling::exit() {
+}
+
+bling::flashall() {
+}
+
+bling::rows() {
+}
+
+bling::columns() {
+}
+
+bling::msg() {
+}
+
+bling::scrollmsg() {
+}
+
+// Based on the current bling mode, do whatever it is you are going to do
+bling::run() {
+
+}
+
+// etc
diff --git a/libs/surfaces/tranzport/button_events.cc b/libs/surfaces/tranzport/button_events.cc
new file mode 100644
index 0000000000..37c62a6ab7
--- /dev/null
+++ b/libs/surfaces/tranzport/button_events.cc
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_common.h>
+#include <tranzport_control_protocol.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+
+
+void
+TranzportControlProtocol::button_event_battery_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_battery_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_backlight_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_backlight_release (bool shifted)
+{
+#if DEBUG_TRANZPORT
+ printf("backlight released, redrawing (and possibly crashing) display\n");
+#endif
+ if (shifted) {
+ lcd_damage();
+ lcd_clear();
+ last_where += 1; /* force time redisplay */
+ last_track_gain = FLT_MAX;
+ }
+}
+
+void
+TranzportControlProtocol::button_event_trackleft_press (bool shifted)
+{
+ prev_track ();
+ // not really the right layer for this
+ if(display_mode == DisplayBigMeter) {
+ if (route_table[0] != 0) {
+ notify(route_get_name (0).substr (0, 15).c_str());
+ }
+ }
+}
+
+void
+TranzportControlProtocol::button_event_trackleft_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackright_press (bool shifted)
+{
+ next_track ();
+ // not really the right layer for this
+ if(display_mode == DisplayBigMeter) {
+ if (route_table[0] != 0) {
+ notify(route_get_name (0).substr (0, 15).c_str());
+ }
+ }
+}
+
+void
+TranzportControlProtocol::button_event_trackright_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackrec_press (bool shifted)
+{
+ if (shifted) {
+ toggle_all_rec_enables ();
+ } else {
+ route_set_rec_enable (0, !route_get_rec_enable (0));
+ }
+}
+
+void
+TranzportControlProtocol::button_event_trackrec_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackmute_press (bool shifted)
+{
+ if (shifted) {
+ // Mute ALL? Something useful when a phone call comes in. Mute master?
+ } else {
+ route_set_muted (0, !route_get_muted (0));
+ }
+}
+
+void
+TranzportControlProtocol::button_event_trackmute_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
+{
+#if DEBUG_TRANZPORT
+ printf("solo pressed\n");
+#endif
+ if (display_mode == DisplayBigMeter) {
+ light_off (LightAnysolo);
+ return;
+ }
+
+ if (shifted) {
+ session->set_all_solo (!session->soloing());
+ } else {
+ route_set_soloed (0, !route_get_soloed (0));
+ }
+}
+
+void
+TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
+{
+#if DEBUG_TRANZPORT
+ printf("solo released\n");
+#endif
+}
+
+void
+TranzportControlProtocol::button_event_undo_press (bool shifted)
+{
+// undohistory->get_state(1);
+//XMLNode&
+//UndoHistory::get_state (uint32_t depth)
+
+ if (shifted) {
+ redo (); // someday flash the screen with what was redone
+ notify("Redone!!");
+ } else {
+ undo (); // someday flash the screen with what was undone
+ notify("Undone!!");
+ }
+}
+
+void
+TranzportControlProtocol::button_event_undo_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_in_press (bool shifted)
+{
+ if (shifted) {
+ toggle_punch_in ();
+ } else {
+ ControlProtocol::ZoomIn (); /* EMIT SIGNAL */
+ }
+}
+
+void
+TranzportControlProtocol::button_event_in_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_out_press (bool shifted)
+{
+ if (shifted) {
+ toggle_punch_out ();
+ } else {
+ ControlProtocol::ZoomOut (); /* EMIT SIGNAL */
+ }
+}
+
+void
+TranzportControlProtocol::button_event_out_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_punch_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_punch_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_loop_press (bool shifted)
+{
+ if (shifted) {
+ next_wheel_shift_mode ();
+ } else {
+ loop_toggle ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_loop_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_prev_press (bool shifted)
+{
+ if (shifted) {
+ ControlProtocol::ZoomToSession (); /* EMIT SIGNAL */
+ } else {
+ prev_marker ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_prev_release (bool shifted)
+{
+}
+
+// Note - add_marker should adhere to the snap to setting
+// maybe session->audible_frame does that
+
+void
+TranzportControlProtocol::button_event_add_press (bool shifted)
+{
+ add_marker ();
+}
+
+void
+TranzportControlProtocol::button_event_add_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_next_press (bool shifted)
+{
+ if (shifted) {
+ next_wheel_mode ();
+ } else {
+ next_marker ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_next_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_rewind_press (bool shifted)
+{
+ if (shifted) {
+ goto_start ();
+ } else {
+ rewind ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_rewind_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_fastforward_press (bool shifted)
+{
+ if (shifted) {
+ goto_end ();
+ } else {
+ ffwd ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_fastforward_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_stop_press (bool shifted)
+{
+ if (shifted) {
+ next_display_mode ();
+ } else {
+ transport_stop ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_stop_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_play_press (bool shifted)
+{
+ if (shifted) {
+ set_transport_speed (1.0f);
+ } else {
+ transport_play ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_play_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_record_press (bool shifted)
+{
+ if (shifted) {
+ save_state ();
+ } else {
+ rec_enable_toggle ();
+ }
+}
+
+void
+TranzportControlProtocol::button_event_record_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_footswitch_press (bool shifted)
+{
+ if (shifted) {
+ next_marker (); // think this through, we could also do punch in
+ } else {
+ prev_marker (); // think this through, we could also do punch in
+ }
+}
+
+void
+TranzportControlProtocol::button_event_footswitch_release (bool shifted)
+{
+ if(session->transport_speed() == 0.0)
+ {
+ transport_play ();
+ }
+}
+
+// Possible new api example
+// tries harder to do the right thing if we somehow missed a button down event
+// which currently happens... a lot.
+
+void button_event_mute (bool pressed, bool shifted)
+{
+ static int was_pressed = 0;
+ if((!pressed && !was_pressed) || pressed) {
+ was_pressed = 1;
+ }
+
+ was_pressed = 0;
+}
diff --git a/libs/surfaces/tranzport/button_yn.cc b/libs/surfaces/tranzport/button_yn.cc
new file mode 100644
index 0000000000..04b6ab5668
--- /dev/null
+++ b/libs/surfaces/tranzport/button_yn.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* placeholder for button definitions for user edits like yes/no */
diff --git a/libs/surfaces/tranzport/buttons.cc b/libs/surfaces/tranzport/buttons.cc
new file mode 100644
index 0000000000..df5a88e6d9
--- /dev/null
+++ b/libs/surfaces/tranzport/buttons.cc
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 "tranzport_control_protocol.h"
+
+#define TRANZPORT_BUTTON_HANDLER(callback, button_arg) if (button_changes & button_arg) { \
+ if (buttonmask & button_arg) { \
+ callback##_press (buttonmask&ButtonShift); } else { callback##_release (buttonmask&ButtonShift); } }
+
+int
+TranzportControlProtocol::process (uint8_t* buf)
+{
+
+ uint32_t this_button_mask;
+ uint32_t button_changes;
+
+ _device_status = buf[1];
+
+#if DEBUG_TRANZPORT > 10
+ // Perhaps the device can go offline due to flow control, print command bits to see if we have anything interesting
+ if(_device_status == STATUS_ONLINE) {
+ printf("ONLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+ if(_device_status == STATUS_OFFLINE) {
+ printf("OFFLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+
+ if(_device_status != STATUS_OK) { return 1; }
+
+#endif
+
+
+ this_button_mask = 0;
+ this_button_mask |= buf[2] << 24;
+ this_button_mask |= buf[3] << 16;
+ this_button_mask |= buf[4] << 8;
+ this_button_mask |= buf[5];
+ _datawheel = buf[6];
+
+#if DEBUG_TRANZPORT_STATE > 1
+ // Is the state machine incomplete?
+ const unsigned int knownstates = 0x00004000|0x00008000|
+ 0x04000000| 0x40000000| 0x00040000| 0x00400000|
+ 0x00000400| 0x80000000| 0x02000000| 0x20000000|
+ 0x00800000| 0x00080000| 0x00020000| 0x00200000|
+ 0x00000200| 0x01000000| 0x10000000| 0x00010000|
+ 0x00100000| 0x00000100| 0x08000000| 0x00001000;
+
+ std::bitset<32> bi(knownstates);
+ std::bitset<32> vi(this_button_mask);
+
+ // if an bi & vi == vi the same - it's a valid set
+
+ if(vi != (bi & vi)) {
+ printf("UNKNOWN STATE: %s also, datawheel= %d\n", vi.to_string().c_str(), _datawheel);
+ }
+#endif
+
+ button_changes = (this_button_mask ^ buttonmask);
+ buttonmask = this_button_mask;
+
+ if (_datawheel) {
+ datawheel ();
+ }
+
+ // SHIFT + STOP + PLAY for bling mode?
+ // if (button_changes & ButtonPlay & ButtonStop) {
+ // bling_mode_toggle();
+ // } or something like that
+
+ TRANZPORT_BUTTON_HANDLER(button_event_battery,ButtonBattery);
+ TRANZPORT_BUTTON_HANDLER(button_event_backlight,ButtonBacklight);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackleft,ButtonTrackLeft);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackright,ButtonTrackRight);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackrec,ButtonTrackRec);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackmute,ButtonTrackMute);
+ TRANZPORT_BUTTON_HANDLER(button_event_tracksolo,ButtonTrackSolo);
+ TRANZPORT_BUTTON_HANDLER(button_event_undo,ButtonUndo);
+ TRANZPORT_BUTTON_HANDLER(button_event_in,ButtonIn);
+ TRANZPORT_BUTTON_HANDLER(button_event_out,ButtonOut);
+ TRANZPORT_BUTTON_HANDLER(button_event_punch,ButtonPunch);
+ TRANZPORT_BUTTON_HANDLER(button_event_loop,ButtonLoop);
+ TRANZPORT_BUTTON_HANDLER(button_event_prev,ButtonPrev);
+ TRANZPORT_BUTTON_HANDLER(button_event_add,ButtonAdd);
+ TRANZPORT_BUTTON_HANDLER(button_event_next,ButtonNext);
+ TRANZPORT_BUTTON_HANDLER(button_event_rewind,ButtonRewind);
+ TRANZPORT_BUTTON_HANDLER(button_event_fastforward,ButtonFastForward);
+ TRANZPORT_BUTTON_HANDLER(button_event_stop,ButtonStop);
+ TRANZPORT_BUTTON_HANDLER(button_event_play,ButtonPlay);
+ TRANZPORT_BUTTON_HANDLER(button_event_record,ButtonRecord);
+ TRANZPORT_BUTTON_HANDLER(button_event_footswitch,ButtonFootswitch);
+ return 0;
+}
+
diff --git a/libs/surfaces/tranzport/general.cc b/libs/surfaces/tranzport/general.cc
new file mode 100644
index 0000000000..103a3b7681
--- /dev/null
+++ b/libs/surfaces/tranzport/general.cc
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_common.h>
+#include <tranzport_control_protocol.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+// HA, I don't need this anymore
+#include <slider_gain.h>
+
+// FIXME, flash recording light when recording and transport is moving
+int TranzportControlProtocol::lights_show_recording()
+{
+ return lights_show_normal();
+}
+
+void TranzportControlProtocol::show_bling() {
+ lights_show_bling();
+ screen_show_bling();
+}
+
+void TranzportControlProtocol::notify(const char *msg) {
+ last_notify=100;
+ if(strlen(msg) < 21) {
+ strcpy(last_notify_msg,msg);
+ } else {
+ strncpy(last_notify_msg,msg,16);
+ last_notify_msg[16] = '\n';
+ }
+}
+
+void TranzportControlProtocol::show_notify() {
+// FIXME: Get width of the notify area somehow
+ if(last_notify==0) {
+ print(1,0," ");
+ last_notify=-1;
+ }
+ if(last_notify > 0) {
+ print(1,0,last_notify_msg);
+ --last_notify;
+ }
+}
+
+// Need more bling!
+
+int TranzportControlProtocol::lights_show_bling()
+{
+ switch (bling_mode) {
+ case BlingOff: break;
+ case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
+ case BlingRotating: break; // switch between lights
+ case BlingPairs: break; // Show pairs of lights
+ case BlingRows: break; // light each row in sequence
+ case BlingFlashAll: break; // Flash everything randomly
+ case BlingEnter: lights_on(); // Show intro
+ case BlingExit:
+ lights_off();
+ break;
+ }
+ return 0;
+}
+
+int TranzportControlProtocol::screen_show_bling()
+{
+ switch (bling_mode) {
+ case BlingOff: break;
+ case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
+ case BlingRotating: break; // switch between lights
+ case BlingPairs: break; // Show pairs of lights
+ case BlingRows: break; // light each row in sequence
+ case BlingFlashAll: break; // Flash everything randomly
+ case BlingEnter: // Show intro
+ print(0,0,"!!Welcome to Ardour!");
+ print(1,0,"Peace through Music!");
+ break;
+ case BlingExit:
+ break;
+ }
+ return 0;
+}
+
+int TranzportControlProtocol::lights_show_normal()
+{
+ /* Track only */
+
+ if (route_table[0]) {
+ boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
+ lights_pending[LightTrackrec] = at && at->record_enabled();
+ lights_pending[LightTrackmute] = route_get_muted(0);
+ lights_pending[LightTracksolo] = route_get_soloed(0);
+ } else {
+ lights_pending[LightTrackrec] = false;
+ lights_pending[LightTracksolo] = false;
+ lights_pending[LightTrackmute] = false;
+ }
+
+ /* Global settings */
+
+ lights_pending[LightLoop] = session->get_play_loop();
+ lights_pending[LightPunch] = Config->get_punch_in() || Config->get_punch_out();
+ lights_pending[LightRecord] = session->get_record_enabled();
+ lights_pending[LightAnysolo] = session->soloing();
+
+ return 0;
+}
+
+int TranzportControlProtocol::lights_show_tempo()
+{
+ // someday soon fiddle with the lights more sanely based on the tempo
+ return lights_show_normal();
+}
+
+int
+TranzportControlProtocol::update_state ()
+{
+ /* do the text and light updates */
+
+ switch (display_mode) {
+ case DisplayBigMeter:
+ lights_show_tempo();
+ show_meter ();
+ break;
+
+ case DisplayNormal:
+ lights_show_normal();
+ normal_update();
+ break;
+
+ case DisplayConfig:
+ break;
+
+ case DisplayRecording:
+ lights_show_recording();
+ normal_update();
+ break;
+
+ case DisplayRecordingMeter:
+ lights_show_recording();
+ show_meter();
+ break;
+
+ case DisplayBling:
+ show_bling();
+ break;
+
+ case DisplayBlingMeter:
+ lights_show_bling();
+ show_meter();
+ break;
+ }
+ show_notify();
+
+ return 0;
+
+}
+
+void
+TranzportControlProtocol::prev_marker ()
+{
+ Location *location = session->locations()->first_location_before (session->transport_frame());
+
+ if (location) {
+ session->request_locate (location->start(), session->transport_rolling());
+ notify(location->name().c_str());
+ } else {
+ session->goto_start ();
+ notify("START");
+ }
+
+}
+
+void
+TranzportControlProtocol::next_marker ()
+{
+ Location *location = session->locations()->first_location_after (session->transport_frame());
+
+ if (location) {
+ session->request_locate (location->start(), session->transport_rolling());
+ notify(location->name().c_str());
+ } else {
+ session->request_locate (session->current_end_frame());
+ notify("END ");
+ }
+}
+
+
+void
+TranzportControlProtocol::show_current_track ()
+{
+ char pad[COLUMNS];
+ char *v;
+ int len;
+ if (route_table[0] == 0) {
+ print (0, 0, "---------------");
+ last_track_gain = FLT_MAX;
+ } else {
+ strcpy(pad," ");
+ v = (char *)route_get_name (0).substr (0, 14).c_str();
+ if((len = strlen(v)) > 0) {
+ strncpy(pad,(char *)v,len);
+ }
+ print (0, 0, pad);
+ }
+}
+
+
+#if 0
+void
+TranzportControlProtocol::step_gain (float increment)
+{
+// FIXME: buttonstop is used elsewhere
+ if (buttonmask & ButtonStop) {
+ gain_fraction += 0.001*increment;
+ } else {
+ gain_fraction += 0.01*increment;
+ }
+
+ if (fabsf(gain_fraction) > 2.0) {
+ gain_fraction = 2.0*sign(gain_fraction);
+ }
+
+ route_set_gain (0, slider_position_to_gain (gain_fraction));
+}
+#endif
+
+void
+TranzportControlProtocol::step_gain_up ()
+{
+ if (buttonmask & ButtonStop) {
+ gain_fraction += 0.001;
+ } else {
+ gain_fraction += 0.01;
+ }
+
+ if (gain_fraction > 2.0) {
+ gain_fraction = 2.0;
+ }
+
+ route_set_gain (0, slider_position_to_gain (gain_fraction));
+}
+
+void
+TranzportControlProtocol::step_gain_down ()
+{
+ if (buttonmask & ButtonStop) {
+ gain_fraction -= 0.001;
+ } else {
+ gain_fraction -= 0.01;
+ }
+
+ if (gain_fraction < 0.0) {
+ gain_fraction = 0.0;
+ }
+
+ route_set_gain (0, slider_position_to_gain (gain_fraction));
+}
+
+
+void
+TranzportControlProtocol::next_track ()
+{
+ ControlProtocol::next_track (current_track_id);
+ gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
+// notify("NextTrak"); // not needed til we have more modes
+}
+
+void
+TranzportControlProtocol::prev_track ()
+{
+ ControlProtocol::prev_track (current_track_id);
+ gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
+// notify("PrevTrak");
+}
+
+// This should kind of switch to using notify
+
+// Was going to keep state around saying to retry or not
+// haven't got to it yet, still not sure it's a good idea
+
+void
+TranzportControlProtocol::print (int row, int col, const char *text) {
+ print_noretry(row,col,text);
+}
+
+// -1 on failure
+// 0 on no damage
+// count of bit set on damage?
+
+void
+TranzportControlProtocol::print_noretry (int row, int col, const char *text)
+{
+ uint32_t length = strlen (text);
+ if (row*COLUMNS+col+length > (ROWS*COLUMNS)) {
+ return;
+ }
+ // FIXME - be able to print the whole screen at a go.
+ uint32_t t,r,c;
+ std::bitset<ROWS*COLUMNS> mask(screen_invalid);
+ for(r = row, c = col, t = 0 ; t < length; c++,t++) {
+ screen_pending[r][c] = text[t];
+ mask[r*COLUMNS+c] = (screen_current[r][c] != screen_pending[r][c]);
+ }
+ screen_invalid = mask;
+}
+
+void TranzportControlProtocol::invalidate()
+{
+ lcd_damage(); lights_invalidate(); screen_invalidate(); // one of these days lcds can be fine but screens not
+}
diff --git a/libs/surfaces/tranzport/init.cc b/libs/surfaces/tranzport/init.cc
new file mode 100644
index 0000000000..94f85bdc56
--- /dev/null
+++ b/libs/surfaces/tranzport/init.cc
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_common.h>
+#include <tranzport_control_protocol.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+void*
+TranzportControlProtocol::_monitor_work (void* arg)
+{
+ return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
+}
+
+TranzportControlProtocol::~TranzportControlProtocol ()
+{
+ set_active (false);
+}
+
+int TranzportControlProtocol::rtpriority_set(int priority)
+{
+ struct sched_param rtparam;
+ int err;
+ char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
+ // Note - try SCHED_RR with a low limit
+ // - we don't care if we can't write everything this ms
+ // and it will help if we lose the device
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ return 1;
+ }
+ return 0;
+}
+
+// Running with realtime privs is bad when you have problems
+
+int TranzportControlProtocol::rtpriority_unset(int priority)
+{
+ struct sched_param rtparam;
+ int err;
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = priority;
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ return 1;
+ }
+ PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
+ return 0;
+}
+
+
+int
+TranzportControlProtocol::set_active (bool yn)
+{
+ if (yn != _active) {
+
+ if (yn) {
+
+ if (open ()) {
+ return -1;
+ }
+
+ if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
+ _active = true;
+#if TRANZPORT_THREADS
+ if (pthread_create_and_store (X_("tranzport read"), &thread_read, 0, _read_work, this) == 0) {
+ _active_read = true;
+ if (pthread_create_and_store (X_("tranzport write"), &thread_write, 0, _write_work, this) == 0) {
+ _active_write = true;
+ if (pthread_create_and_store (X_("tranzport process"), &thread_process, 0, _process_work, this) == 0) {
+ _active_process = true;
+ if (pthread_create_and_store (X_("tranzport timer"), &thread_timer, 0, _process_timer, this) == 0) {
+ _active_process = true;
+#endif
+ } else {
+ return -1;
+ }
+
+ } else {
+ cerr << "Begin tranzport shutdown\n";
+// if we got here due to an error, prettifying things will only make it worse
+// And with threads involved, oh boy...
+ if(!(last_write_error || last_read_error)) {
+ bling_mode = BlingExit;
+ enter_bling_mode();
+// thread FIXME - wait til all writes are done
+ for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
+ }
+#if TRANZPORT_THREADS
+ pthread_cancel_one (_thread_timer);
+ pthread_cancel_one (_thread_process);
+ pthread_cancel_one (_thread_read);
+ pthread_cancel_one (_thread_write);
+#endif
+ pthread_cancel_one (thread);
+
+ cerr << "Tranzport Thread dead\n";
+ close ();
+ _active = false;
+ cerr << "End tranzport shutdown\n";
+ }
+ }
+
+ return 0;
+}
+
+TranzportControlProtocol::TranzportControlProtocol (Session& s)
+ : ControlProtocol (s, X_("Tranzport"))
+{
+ /* tranzport controls one track at a time */
+
+ set_route_table_size (1);
+ timeout = 6000; // what is this for?
+ buttonmask = 0;
+ _datawheel = 0;
+ _device_status = STATUS_OFFLINE;
+ udev = 0;
+ current_track_id = 0;
+ last_where = max_frames;
+ wheel_mode = WheelTimeline;
+ wheel_shift_mode = WheelShiftGain;
+ wheel_increment = WheelIncrScreen;
+ bling_mode = BlingEnter;
+ last_notify_msg[0] = '\0';
+ last_notify = 0;
+ timerclear (&last_wheel_motion);
+ last_wheel_dir = 1;
+ last_track_gain = FLT_MAX;
+ last_write_error = 0;
+ last_read_error = 0;
+ display_mode = DisplayBling;
+ gain_fraction = 0.0;
+ invalidate();
+ screen_init();
+ lights_init();
+// FIXME: Wait til device comes online somewhere
+// About 3 reads is enough
+// enter_bling_mode();
+
+}
+
+void*
+TranzportControlProtocol::monitor_work ()
+{
+ uint8_t buf[8]; // = { 0,0,0,0,0,0,0,0 };
+ int val = 0, pending = 0;
+ bool first_time = true;
+ uint8_t offline = 0;
+
+ PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+ rtpriority_set();
+ inflight=0;
+ //int intro = 20;
+
+ // wait for the device to come online
+ invalidate();
+ screen_init();
+ lights_init();
+ update_state();
+// There has to be some specific command to enable the device!!
+// while((val = read(buf,DEFAULT_USB_TIMEOUT*5)) == -110 && pending !=0) {
+// pending = lights_flush(); // poke the device for a while
+// }
+
+// pending = 1;
+// while(intro-- > 0 && pending != 0) {
+// usleep(1000);
+// pending = screen_flush(); // kinder, gentler init
+// }
+// usleep(1000);
+// lights_on();
+// while(flush()!=0) ;
+// lights_off();
+ display_mode = DisplayNormal;
+
+ while (true) {
+
+ /* bInterval for this beastie is 10ms */
+
+ if (_device_status == STATUS_OFFLINE) {
+ first_time = true; offline++;
+#if TRANZPORT_DEBUG > 3
+ if(offline == 1) {
+ cerr << "Transport has gone offline\n";
+ }
+#endif
+ } else {
+ offline = 0; // hate writing this
+ }
+ unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
+ switch (s) {
+ case 0: val = read(buf,DEFAULT_USB_TIMEOUT); break;
+ case 1: val = read(buf,DEFAULT_USB_TIMEOUT); break;
+ case 2: val = read(buf,DEFAULT_USB_TIMEOUT); break;
+ case 3: val = read(buf,DEFAULT_USB_TIMEOUT*2); break; // Hoo, boy, we're in trouble
+ default: break; // not reached
+ }
+
+#if DEBUG_TRANZPORT_BITS > 9
+ if(_device_status != STATUS_OFFLINE && _device_status != STATUS_ONLINE && _device_status != STATUS_OK) {
+ printf("The device has more status bits than off or online: %d\n",_device_status);
+ }
+#endif
+
+#if DEBUG_TRANZPORT_BITS > 99
+ if (val != 8) {
+ printf("val = %d errno = %d\n",val,errno);
+ buf[0] = buf[1] = buf[2] = buf[3] =
+ buf[4] = buf[5] = buf[6] = buf[7] =
+ buf[8] = 0;
+ }
+#endif
+
+ if(val == 8) {
+ last_write_error = 0;
+ process (buf);
+ }
+
+#if DEBUG_TRANZPORT > 9
+ if(inflight > 1) printf("Inflight: %d\n", inflight);
+#endif
+
+ if (_device_status == STATUS_ONLINE) {
+ if (first_time) {
+ invalidate();
+ lcd_clear ();
+ lights_off ();
+ first_time = false;
+ last_write_error = 0;
+ offline = 0;
+ pending = 3; // Give some time for the device to recover
+ }
+#if DEBUG_TRANZPORT_BITS > 10
+ // Perhaps an online message indicates something
+
+ if(_device_status != buf[1]) {
+ printf("WTF- val: %d, device status != buf! %d != %d \n",val,_device_status,buf[1]); _device_status = buf[1];
+ }
+#endif
+
+ }
+
+#if DEBUG_TRANZPORT_BITS > 10
+
+ if(val == 8) {
+
+ if(_device_status == STATUS_ONLINE) {
+ printf("ONLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+ if(_device_status == STATUS_OFFLINE) {
+ printf("OFFLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+
+ if(_device_status == STATUS_OK) {
+ printf("OK : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+
+ }
+
+#endif
+
+ /* update whatever needs updating */
+ if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
+ update_state ();
+
+ /* still struggling with a good means of exerting flow control without having to create threads */
+ // pending = flush();
+
+ if(pending == 0) {
+ pending = flush();
+ } else {
+ if(inflight > 0) {
+ pending = --inflight; // we just did a whole bunch of writes so wait
+ } else {
+ pending = 0;
+ }
+ }
+ }
+ // pending = 0;
+ }
+ return (void*) 0;
+}
+
diff --git a/libs/surfaces/tranzport/interface.cc b/libs/surfaces/tranzport/interface.cc
index f6d0dc8206..f9b82fa651 100644
--- a/libs/surfaces/tranzport/interface.cc
+++ b/libs/surfaces/tranzport/interface.cc
@@ -1,3 +1,23 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <control_protocol/control_protocol.h>
#include "tranzport_control_protocol.h"
diff --git a/libs/surfaces/tranzport/io.cc b/libs/surfaces/tranzport/io.cc
new file mode 100644
index 0000000000..14242ea0ec
--- /dev/null
+++ b/libs/surfaces/tranzport/io.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* The routines in here should know absolutely nothing about how io is actually done */
+
+#include <tranzport_control_protocol.h>
+
+int
+TranzportControlProtocol::flush ()
+{
+ int pending = 0;
+
+// Always write the lights first
+ if(!(pending = lights_flush())) {
+ pending = screen_flush();
+ }
+
+#if DEBUG_TRANZPORT_BITS > 9
+ int s;
+ if(s = (screen_invalid.count())) { // + lights_invalid.count())) {
+ printf("VALID : %s %s\n",
+ screen_invalid.to_string().c_str(),
+ lights_invalid.to_string().c_str());
+ printf("CURR : %s %s\n",
+ screen_invalid.to_string().c_str(),
+ lights_current.to_string().c_str());
+ printf("PENDING : %s %s\n",
+ screen_invalid.to_string().c_str(),
+ lights_pending.to_string().c_str());
+#if DEBUG_TRANZPORT_BITS > 10
+ printf("invalid bits: %d\n",s);
+#endif
+ }
+#endif
+ return pending;
+}
+
+
+int
+TranzportControlProtocol::lights_flush ()
+{
+ std::bitset<LIGHTS> light_state;
+ light_state = lights_pending ^ lights_current;
+ if ( (light_state.none() || lights_invalid.none()))
+ {
+ return (0);
+ }
+
+#if DEBUG_TRANZPORT_LIGHTS
+ printf("LPEND : %s\n", lights_pending.to_string().c_str());
+ printf("LCURR : %s\n", lights_current.to_string().c_str());
+#endif
+
+ // if ever we thread reads/writes STATUS_OK will have to move into the loop
+ int i;
+
+ if ( _device_status == STATUS_OK || _device_status == STATUS_ONLINE) {
+ for (i = 0; i<LIGHTS; i++) {
+ if(light_state[i]) {
+ if(light_set ((LightID)i,lights_pending[i])) {
+#if DEBUG_TRANZPORT_LIGHTS > 2
+ printf("Did %d light writes\n",i);
+#endif
+ return light_state.count();
+ } else {
+ light_state[i] = 0;
+ }
+
+ }
+ }
+ }
+ light_state = lights_pending ^ lights_current;
+#if DEBUG_TRANZPORT_LIGHTS > 2
+ printf("Did %d light writes, left: %d\n",i, light_state.count());
+#endif
+
+ return light_state.count();
+}
diff --git a/libs/surfaces/tranzport/io_kernel.cc b/libs/surfaces/tranzport/io_kernel.cc
new file mode 100644
index 0000000000..5e29e9ac7b
--- /dev/null
+++ b/libs/surfaces/tranzport/io_kernel.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+#if HAVE_TRANZPORT_KERNEL_DRIVER
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+#include "tranzport_control_protocol.h"
+
+// Something like open(/dev/surface/tranzport/event) for reading and raw for writing) would be better in the long run
+// Also support for multiple tranzports needs to be figured out
+// And bulk reads/writes in general
+
+bool
+TranzportControlProtocol::probe ()
+{
+ if((udev = ::open(TRANZPORT_DEVICE,O_RDWR))> 0) {
+ ::close(udev);
+ return true;
+ }
+ error << _("Tranzport: Can't open device for Read/Write: ") << endmsg;
+ return false;
+}
+
+int
+TranzportControlProtocol::open ()
+{
+ if((udev=::open(TRANZPORT_DEVICE,O_RDWR))> 0) {
+ return(udev);
+ }
+ error << _("Tranzport: no device detected") << endmsg;
+ return udev;
+}
+
+int
+TranzportControlProtocol::close ()
+{
+ int ret = 0;
+
+ if (udev < 1) {
+ return 0;
+ }
+
+ if ((ret = ::close (udev)) != 0) {
+ error << _("Tranzport: cannot close device") << endmsg;
+ }
+
+ return ret;
+}
+
+// someday do buffered reads, presently this does blocking reads, which is bad...
+
+int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override)
+{
+ last_read_error = ::read (udev, (char *) buf, 8);
+ switch(errno) {
+ case -ENOENT:
+ case -ENXIO:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENODEV:
+ cerr << "Tranzport disconnected, errno: " << last_read_error;
+ set_active(false);
+ break;
+ case -ETIMEDOUT: // This is not normal, but lets see what happened
+ cerr << "Tranzport read timed out, errno: " << last_read_error;
+ break;
+ default:
+#if DEBUG_TRANZPORT
+ cerr << "Got an unknown error on read:" << last_read_error "\n";
+#endif
+ break;
+ }
+
+ return last_read_error;
+}
+
+
+int
+TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
+{
+ // inflight is now taken care of by the driver, but...
+ if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
+ int val = ::write (udev, (char*) cmd, 8);
+
+ if (val < 0 && val !=8) {
+#if DEBUG_TRANZPORT
+ printf("write failed: %d\n", val);
+#endif
+ last_write_error = errno;
+ switch(last_write_error) {
+ case -ENOENT:
+ case -ENXIO:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENODEV:
+ cerr << "Tranzport disconnected, errno: " << last_write_error;
+ set_active(false);
+ break;
+ case -ETIMEDOUT: // This is not normal but
+ cerr << "Tranzport disconnected, errno: " << last_write_error;
+ break;
+ default:
+#if DEBUG_TRANZPORT
+ cerr << "Got an unknown error on read:" << last_write_error "\n";
+#endif
+ break;
+ }
+ return last_write_error;
+ }
+
+ last_write_error = 0;
+ ++inflight;
+
+ return 0;
+
+}
+
+int
+TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
+{
+ return (write_noretry(cmd,timeout_override));
+}
+
+// FIXME - install poll semantics
+#endif /* HAVE_TRANZPORT_KERNEL_DRIVER */
+
diff --git a/libs/surfaces/tranzport/io_midi.cc b/libs/surfaces/tranzport/io_midi.cc
new file mode 100644
index 0000000000..0fd10cfbf3
--- /dev/null
+++ b/libs/surfaces/tranzport/io_midi.cc
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* io_midi: Implements reading and writing tranzport events via the normal
+ tranzport midi specification */
+
+/* One day
+#include <tranzport_control_protocol.h>
+*/
diff --git a/libs/surfaces/tranzport/io_usb.cc b/libs/surfaces/tranzport/io_usb.cc
new file mode 100644
index 0000000000..c4a004a160
--- /dev/null
+++ b/libs/surfaces/tranzport/io_usb.cc
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <iostream>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <tranzport_control_protocol.h>
+
+#if !HAVE_TRANZPORT_KERNEL_DRIVER
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+// I note that these usb specific open, close, probe, read routines are basically
+// pure boilerplate and could easily be abstracted elsewhere
+
+bool
+TranzportControlProtocol::probe ()
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_busses; bus; bus = bus->next) {
+
+ for(dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+int
+TranzportControlProtocol::open ()
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_busses; bus; bus = bus->next) {
+
+ for(dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor != VENDORID)
+ continue;
+ if (dev->descriptor.idProduct != PRODUCTID)
+ continue;
+ return open_core (dev);
+ }
+ }
+
+ cerr << _("Tranzport: no device detected") << endmsg;
+ return -1;
+}
+
+int
+TranzportControlProtocol::open_core (struct usb_device* dev)
+{
+ if (!(udev = usb_open (dev))) {
+ cerr << _("Tranzport: cannot open USB transport") << endmsg;
+ return -1;
+ }
+
+ if (usb_claim_interface (udev, 0) < 0) {
+ cerr << _("Tranzport: cannot claim USB interface") << endmsg;
+ usb_close (udev);
+ udev = 0;
+ return -1;
+ }
+
+ if (usb_set_configuration (udev, 1) < 0) {
+ cerr << _("Tranzport: cannot configure USB interface") << endmsg;
+ }
+
+ return 0;
+}
+
+int
+TranzportControlProtocol::close ()
+{
+ int ret = 0;
+
+ if (udev == 0) {
+ return 0;
+ }
+
+ if (usb_release_interface (udev, 0) < 0) {
+ cerr << _("Tranzport: cannot release interface") << endmsg;
+ ret = -1;
+ }
+
+ if (usb_close (udev)) {
+ cerr << _("Tranzport: cannot close device") << endmsg;
+ udev = 0;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override)
+{
+ last_read_error = usb_interrupt_read (udev, READ_ENDPOINT, (char *) buf, 8, timeout_override);
+ switch(last_read_error) {
+ case -ENOENT:
+ case -ENXIO:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENODEV:
+ cerr << "Tranzport disconnected, errno: " << last_read_error;
+ set_active(false);
+ case -ETIMEDOUT: // This is normal
+ break;
+ default:
+#if DEBUG_TRANZPORT
+ cerr << "Got an unknown error on read:" << last_read_error "\n";
+#endif
+ break;
+ }
+
+ return last_read_error;
+}
+
+
+int
+TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
+{
+ int val;
+ if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
+ val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
+
+ if (val < 0 && val !=8) {
+#if DEBUG_TRANZPORT
+ printf("usb_interrupt_write failed: %d\n", val);
+#endif
+ last_write_error = val;
+ switch(last_write_error) {
+ case -ENOENT:
+ case -ENXIO:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENODEV:
+ cerr << "Tranzport disconnected, errno: " << last_write_error;
+ set_active(false);
+ case -ETIMEDOUT: // This is normal
+ break;
+ default:
+#if DEBUG_TRANZPORT
+ cerr << "Got an unknown error on read:" << last_write_error "\n";
+#endif
+ break;
+ }
+ return val;
+ }
+
+ last_write_error = 0;
+ ++inflight;
+
+ return 0;
+
+}
+
+int
+TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
+{
+#if MAX_RETRY > 1
+ int val;
+ int retry = 0;
+ if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
+
+ while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
+ printf("usb_interrupt_write failed, retrying: %d\n", val);
+ }
+
+ if (retry == MAX_RETRY) {
+ printf("Too many retries on a tranzport write, aborting\n");
+ }
+
+ if (val < 0) {
+ printf("usb_interrupt_write failed: %d\n", val);
+ return val;
+ }
+ if (val != 8) {
+ printf("usb_interrupt_write failed: %d\n", val);
+ return -1;
+ }
+ ++inflight;
+ return 0;
+#else
+ return (write_noretry(cmd,timeout_override));
+#endif
+
+}
+
+#endif
diff --git a/libs/surfaces/tranzport/lcd.cc b/libs/surfaces/tranzport/lcd.cc
new file mode 100644
index 0000000000..88f9ea36d6
--- /dev/null
+++ b/libs/surfaces/tranzport/lcd.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_control_protocol.h>
+
+// doing these functions made me realize that screen_invalid should be lcd_isdamaged FIXME soon
+
+bool TranzportControlProtocol::lcd_damage()
+{
+ screen_invalidate();
+ return true;
+}
+
+bool TranzportControlProtocol::lcd_damage (int row, int col, int length)
+{
+ std::bitset<ROWS*COLUMNS> mask1(0);
+ // there's an intrinsic to do this fast, darn it, or I'm just sleepy
+ for (int i = 0; i < length; i++) { mask1[i] = 1; }
+ std::bitset<ROWS*COLUMNS> mask(mask1 << (row*COLUMNS+col));
+ screen_invalid |= mask;
+ return true;
+}
+
+// Still working on the layering, arguably screen_invalid should be lcd_invalid
+// or vice versa
+
+bool TranzportControlProtocol::lcd_isdamaged ()
+{
+ if(screen_invalid.any()) {
+#if DEBUG_TRANZPORT > 5
+ printf("LCD is damaged somewhere, should redraw it\n");
+#endif
+ return true;
+ }
+ return false;
+}
+
+bool TranzportControlProtocol::lcd_isdamaged (int row, int col, int length)
+{
+ // there's an intrinsic to do this fast, darn it
+ std::bitset<ROWS*COLUMNS> mask1(0);
+ for (int i = 0; i < length; i++) { mask1[i] = 1; }
+ std::bitset<ROWS*COLUMNS> mask(mask1 << (row*COLUMNS+col));
+ mask &= screen_invalid;
+ if(mask.any()) {
+#if DEBUG_TRANZPORT > 5
+ printf("row: %d,col: %d is damaged, should redraw it\n", row,col);
+#endif
+ return true;
+ }
+ return false;
+}
+
+// lcd_clear would be a separate function for a smart display
+// here it does nothing, but for the sake of completeness it should
+// probably write the lcd, and while I'm on the topic it should probably
+// take a row, col, length argument....
+
+void
+TranzportControlProtocol::lcd_clear ()
+{
+
+}
+
+// These lcd commands are not universally used yet and may drop out of the api
+
+int
+TranzportControlProtocol::lcd_flush ()
+{
+ return 0;
+}
+
+int
+TranzportControlProtocol::lcd_write(uint8_t* cmd, uint32_t timeout_override)
+{
+ int result;
+#if (DEBUG_TRANZPORT_SCREEN > 0)
+ printf("VALID : %s\n", (screen_invalid.to_string()).c_str());
+#endif
+ if ((result = write(cmd,timeout_override))) {
+#if DEBUG_TRANZPORT > 4
+ printf("usb screen update failed for some reason... why? \nresult, cmd and data were %d %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ result, cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]);
+#endif
+ }
+ return result;
+}
+
+void
+TranzportControlProtocol::lcd_fill (uint8_t fill_char)
+{
+}
+
+void
+TranzportControlProtocol::lcd_print (int row, int col, const char* text)
+{
+ print(row,col,text);
+}
+
+void TranzportControlProtocol::lcd_print_noretry (int row, int col, const char* text)
+{
+ print(row,col,text);
+}
diff --git a/libs/surfaces/tranzport/lights.cc b/libs/surfaces/tranzport/lights.cc
new file mode 100644
index 0000000000..c0e8092f45
--- /dev/null
+++ b/libs/surfaces/tranzport/lights.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_control_protocol.h>
+
+// Lights are buffered, and arguably these functions should be eliminated or inlined
+
+void
+TranzportControlProtocol::lights_on ()
+{
+ lights_pending.set();
+}
+
+void
+TranzportControlProtocol::lights_off ()
+{
+ lights_pending.reset();
+}
+
+int
+TranzportControlProtocol::light_on (LightID light)
+{
+ lights_pending.set(light);
+ return 0;
+}
+
+int
+TranzportControlProtocol::light_off (LightID light)
+{
+ lights_pending.reset(light);
+ return 0;
+}
+
+void TranzportControlProtocol::lights_init()
+{
+ lights_invalid.set();
+ lights_flash = lights_pending = lights_current.reset();
+}
+
+
+// Now that all this is bitsets, I don't see much
+// need for these 4 to remain in the API
+
+void TranzportControlProtocol::light_validate (LightID light)
+{
+ lights_invalid.reset(light);
+}
+
+void TranzportControlProtocol::light_invalidate (LightID light)
+{
+ lights_invalid.set(light);
+}
+
+void TranzportControlProtocol::lights_validate ()
+{
+ lights_invalid.reset();
+}
+
+void TranzportControlProtocol::lights_invalidate ()
+{
+ lights_invalid.set();
+}
+
+int
+TranzportControlProtocol::light_set (LightID light, bool offon)
+{
+ uint8_t cmd[8];
+ cmd[0] = 0x00; cmd[1] = 0x00; cmd[2] = light; cmd[3] = offon;
+ cmd[4] = 0x00; cmd[5] = 0x00; cmd[6] = 0x00; cmd[7] = 0x00;
+
+ if (write (cmd) == 0) {
+ lights_current[light] = offon;
+ lights_invalid.reset(light);
+ return 0;
+ } else {
+ return 1;
+ }
+}
diff --git a/libs/surfaces/tranzport/meter.cc b/libs/surfaces/tranzport/meter.cc
new file mode 100644
index 0000000000..cc57846058
--- /dev/null
+++ b/libs/surfaces/tranzport/meter.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* Generic support for character based metering on a track */
diff --git a/libs/surfaces/tranzport/mode.cc b/libs/surfaces/tranzport/mode.cc
new file mode 100644
index 0000000000..03d715e66f
--- /dev/null
+++ b/libs/surfaces/tranzport/mode.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_control_protocol.h>
+
+void
+TranzportControlProtocol::normal_update ()
+{
+ show_current_track ();
+ show_transport_time ();
+ show_track_gain ();
+ show_wheel_mode ();
+}
+
+void
+TranzportControlProtocol::next_display_mode ()
+{
+ switch (display_mode) {
+
+ case DisplayNormal:
+ enter_big_meter_mode();
+ break;
+
+ case DisplayBigMeter:
+ enter_normal_display_mode();
+ break;
+
+ case DisplayRecording:
+ enter_normal_display_mode();
+ break;
+
+ case DisplayRecordingMeter:
+ enter_big_meter_mode();
+ break;
+
+ case DisplayConfig:
+ case DisplayBling:
+ case DisplayBlingMeter:
+ enter_normal_display_mode();
+ break;
+ }
+}
+
+// FIXME: There should be both enter and exits
+// EXIT would erase the portions of the screen being written
+// to.
+/* not sure going macro crazy is a good idea
+#define DECLARE_ENTER_MODE(mode,modename) void TranzportControlProtocol::enter_##mode##_mode() \{\screen_clear(); lights_off(); display_mode=Display##modename;\;
+*/
+void
+TranzportControlProtocol::enter_recording_mode ()
+{
+ screen_clear ();
+ lights_off ();
+ display_mode = DisplayRecording;
+}
+
+void
+TranzportControlProtocol::enter_bling_mode ()
+{
+ screen_clear ();
+ lights_off ();
+ display_mode = DisplayBling;
+}
+
+void
+TranzportControlProtocol::enter_config_mode ()
+{
+ lights_off ();
+ screen_clear ();
+ display_mode = DisplayConfig;
+}
+
+
+void
+TranzportControlProtocol::enter_big_meter_mode ()
+{
+ lights_off (); // it will clear the screen for you
+ last_meter_fill = 0;
+ display_mode = DisplayBigMeter;
+}
+
+void
+TranzportControlProtocol::enter_normal_display_mode ()
+{
+ lights_off ();
+ screen_clear ();
+ display_mode = DisplayNormal;
+}
+
diff --git a/libs/surfaces/tranzport/mode_loop.cc b/libs/surfaces/tranzport/mode_loop.cc
new file mode 100644
index 0000000000..b9ea9f239e
--- /dev/null
+++ b/libs/surfaces/tranzport/mode_loop.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* placeholder for Marker Mode: Edit Markers, Setup Loops, and Punch in points */
diff --git a/libs/surfaces/tranzport/mode_tuner.cc b/libs/surfaces/tranzport/mode_tuner.cc
new file mode 100644
index 0000000000..a686f81be1
--- /dev/null
+++ b/libs/surfaces/tranzport/mode_tuner.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* Placeholder for a tuner mode at some point */
diff --git a/libs/surfaces/tranzport/panner.cc b/libs/surfaces/tranzport/panner.cc
new file mode 100644
index 0000000000..4a177db9a7
--- /dev/null
+++ b/libs/surfaces/tranzport/panner.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_common.h>
+#include <tranzport_control_protocol.h>
+
+void
+TranzportControlProtocol::step_pan_right ()
+{
+}
+
+void
+TranzportControlProtocol::step_pan_left ()
+{
+}
+
+
diff --git a/libs/surfaces/tranzport/screen.cc b/libs/surfaces/tranzport/screen.cc
new file mode 100644
index 0000000000..51062de3ad
--- /dev/null
+++ b/libs/surfaces/tranzport/screen.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <tranzport_control_protocol.h>
+
+void
+TranzportControlProtocol::screen_clear ()
+{
+ const char *blank = " ";
+ print(0,0,blank);
+ print(1,0,blank);
+}
+
+void TranzportControlProtocol::screen_invalidate ()
+{
+ screen_invalid.set();
+ for(int row = 0; row < ROWS; row++) {
+ for(int col = 0; col < COLUMNS; col++) {
+ screen_current[row][col] = 0x7f;
+ screen_pending[row][col] = ' ';
+ screen_flash[row][col] = ' ';
+ }
+ }
+}
+
+void TranzportControlProtocol::screen_validate ()
+{
+}
+
+void TranzportControlProtocol::screen_init ()
+{
+ screen_invalidate();
+}
+
+// FIXME: Switch to a column oriented flush to make the redraw of the
+// meters look better
+
+int
+TranzportControlProtocol::screen_flush ()
+{
+ int cell = 0, row=0, col_base, pending = 0;
+ const unsigned long CELL_BITS = 0x0F;
+ if ( _device_status == STATUS_OFFLINE) { return (-1); }
+
+ std::bitset<ROWS*COLUMNS> mask(CELL_BITS);
+ std::bitset<ROWS*COLUMNS> imask(CELL_BITS);
+ for(cell = 0; cell < 10 && pending == 0; cell++) {
+ mask = imask << (cell*4);
+ if((screen_invalid & mask).any()) {
+ /* something in this cell is different, so dump the cell to the device. */
+#if DEBUG_TRANZPORT_SCREEN
+ printf("MASK : %s\n", mask.to_string().c_str());
+#endif
+ if(cell > 4) { row = 1; } else { row = 0; }
+ col_base = (cell*4)%COLUMNS;
+
+ uint8_t cmd[8];
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = screen_pending[row][col_base];
+ cmd[4] = screen_pending[row][col_base+1];
+ cmd[5] = screen_pending[row][col_base+2];
+ cmd[6] = screen_pending[row][col_base+3];
+ cmd[7] = 0x00;
+
+ if((pending = lcd_write(cmd)) == 0) {
+ /* successful write: copy to current cached display */
+ screen_invalid &= mask.flip();
+ memcpy (&screen_current[row][col_base], &screen_pending[row][col_base], 4);
+ }
+ }
+ }
+ return pending;
+}
+
diff --git a/libs/surfaces/tranzport/show.cc b/libs/surfaces/tranzport/show.cc
new file mode 100644
index 0000000000..30c8fbffa9
--- /dev/null
+++ b/libs/surfaces/tranzport/show.cc
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <iostream>
+#include <algorithm>
+#include <cmath>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <pbd/pthread_utils.h>
+
+#include <ardour/route.h>
+#include <ardour/audio_track.h>
+#include <ardour/session.h>
+#include <ardour/tempo.h>
+#include <ardour/location.h>
+#include <ardour/dB.h>
+
+#include <tranzport_control_protocol.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+float
+log_meter (float db)
+{
+ float def = 0.0f; /* Meter deflection %age */
+
+ if (db < -70.0f) return 0.0f;
+ if (db > 6.0f) return 1.0f;
+
+ if (db < -60.0f) {
+ def = (db + 70.0f) * 0.25f;
+ } else if (db < -50.0f) {
+ def = (db + 60.0f) * 0.5f + 2.5f;
+ } else if (db < -40.0f) {
+ def = (db + 50.0f) * 0.75f + 7.5f;
+ } else if (db < -30.0f) {
+ def = (db + 40.0f) * 1.5f + 15.0f;
+ } else if (db < -20.0f) {
+ def = (db + 30.0f) * 2.0f + 30.0f;
+ } else if (db < 6.0f) {
+ def = (db + 20.0f) * 2.5f + 50.0f;
+ }
+
+ /* 115 is the deflection %age that would be
+ when db=6.0. this is an arbitrary
+ endpoint for our scaling.
+ */
+
+ return def/115.0f;
+}
+
+#define TRANZ_U 0x1 /* upper */
+#define TRANZ_BL 0x2 /* lower left */
+#define TRANZ_Q2 0x3 /* 2 quadrant block */
+#define TRANZ_ULB 0x4 /* Upper + lower left */
+#define TRANZ_L 0x5 /* lower */
+#define TRANZ_UBL 0x6 /* upper left + bottom all */
+#define TRANZ_Q4 0x7 /* 4 quadrant block */
+#define TRANZ_UL 0x08 /* upper left */
+
+// Shift Space - switches your "view"
+// Currently defined views are:
+// BigMeter
+//
+// Shift Record - SAVE SNAPSHOT
+// Somewhere I was rewriting this
+// Other meters
+// Inverted - show meters "inside out" For example 4 meters covering 2 cells each, and the
+//
+// each 4 character cell could be an 8 bar meter = 10 meters!
+// Dual Meter mode - master and current track
+// We have 16 rows of pixels so we COULD do a vertical meter
+// BEAT BLOCKS - For each beat, flash a 8 block (could use the center for vertical meters)
+// Could have something generic that could handle up to /20 time
+// Odd times could flash the whole top bar for the first beat
+
+
+// Vertical Meter _ .colon - + ucolon A P R I H FULLBLACK
+// MV@$%&*()-
+
+// 3 char block rotating beat `\'/
+// 1 char rotating beat {/\}
+// 4 char in block rotating beat {/\}
+// {\/)
+
+void TranzportControlProtocol::show_mini_meter()
+{
+ // FIXME - show the current marker in passing
+ const int meter_buf_size = 41;
+ static uint32_t last_meter_fill_l = 0;
+ static uint32_t last_meter_fill_r = 0;
+ uint32_t meter_size;
+
+ float speed = fabsf(session->transport_speed());
+ char buf[meter_buf_size];
+
+ if (speed == 1.0) {
+ meter_size = 32;
+ }
+
+ if (speed == 0.0) {
+ meter_size = 20; // not actually reached
+ }
+
+ if (speed > 0.0 && (speed < 1.0)) {
+ meter_size = 20; // may shrink more one day
+ }
+
+ if (speed > 1.0 && (speed < 2.0)) {
+ meter_size = 20;
+ }
+
+ if (speed >= 2.0) {
+ meter_size = 24;
+ }
+
+
+ // you only seem to get a route_table[0] == 0 on moving forward - bug in next_track?
+
+ if (route_table[0] == 0) {
+ // Principle of least surprise
+ print (1, 0, "NoAUDIO ");
+ return;
+ }
+
+ float level_l = route_get_peak_input_power (0, 0);
+ float fraction_l = log_meter (level_l);
+
+ // how to figure out if we are mono?
+
+ float level_r = route_get_peak_input_power (0, 1);
+ float fraction_r = log_meter (level_r);
+
+ uint32_t fill_left = (uint32_t) floor (fraction_l * ((int) meter_size));
+ uint32_t fill_right = (uint32_t) floor (fraction_r * ((int) meter_size));
+
+ if (fill_left == last_meter_fill_l && fill_right == last_meter_fill_r && !lcd_isdamaged(1,0,meter_size/2)) {
+ /* nothing to do */
+ return;
+ }
+
+ last_meter_fill_l = fill_left; last_meter_fill_r = fill_right;
+
+ // give some feedback when overdriving - override yellow and red lights
+
+ if (fraction_l > 0.96 || fraction_r > 0.96) {
+ light_on (LightLoop);
+ }
+
+ if (fraction_l == 1.0 || fraction_r == 1.0) {
+ light_on (LightTrackrec);
+ }
+
+ const uint8_t char_map[16] = { ' ', TRANZ_UL,
+ TRANZ_U, TRANZ_U,
+ TRANZ_BL, TRANZ_Q2,
+ TRANZ_Q2, TRANZ_ULB,
+ TRANZ_L, TRANZ_UBL,
+ ' ',' ',
+ TRANZ_L, TRANZ_UBL,
+ TRANZ_Q4,TRANZ_Q4
+ };
+ unsigned int val,j,i;
+
+ for(j = 1, i = 0; i < meter_size/2; i++, j+=2) {
+ val = (fill_left >= j) | ((fill_left >= j+1) << 1) |
+ ((fill_right >=j) << 2) | ((fill_right >= j+1) << 3);
+ buf[i] = char_map[val];
+ }
+
+ /* print() requires this */
+
+ buf[meter_size/2] = '\0';
+
+ print (1, 0, buf);
+
+ /* Add a peak bar, someday do falloff */
+
+ // char peak[2]; peak[0] = ' '; peak[1] = '\0';
+ // if(fraction_l == 1.0 || fraction_r == 1.0) peak[0] = 'P';
+ // print (1,8,peak); // Put a peak meter - P in if we peaked.
+
+}
+
+void
+TranzportControlProtocol::show_meter ()
+{
+ // you only seem to get a route_table[0] on moving forward - bug elsewhere
+ if (route_table[0] == 0) {
+ // Principle of least surprise
+ print (0, 0, "No audio to meter!!!");
+ print (1, 0, "Select another track");
+ return;
+ }
+
+ float level = route_get_peak_input_power (0, 0);
+ float fraction = log_meter (level);
+
+ /* Someday add a peak bar*/
+
+ /* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
+ the screen is 20 chars wide, so we can display 40 different levels. compute the level,
+ then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
+ */
+
+ uint32_t fill = (uint32_t) floor (fraction * 40);
+ char buf[21];
+ uint32_t i;
+
+ if (fill == last_meter_fill) {
+ /* nothing to do */
+ return;
+ }
+
+ last_meter_fill = fill;
+
+ bool add_single_level = (fill % 2 != 0);
+ fill /= 2;
+
+ if (fraction > 0.96) {
+ light_on (LightLoop);
+ }
+
+
+ if (fraction == 1.0) {
+ light_on (LightTrackrec);
+ }
+
+
+ /* add all full steps */
+
+ for (i = 0; i < fill; ++i) {
+ buf[i] = 0x07; /* tranzport special code for 4 quadrant LCD block */
+ }
+
+ /* add a possible half-step */
+
+ if (i < 20 && add_single_level) {
+ buf[i] = 0x03; /* tranzport special code for 2 left quadrant LCD block */
+ ++i;
+ }
+
+ /* fill rest with space */
+
+ for (; i < 20; ++i) {
+ buf[i] = ' ';
+ }
+
+ /* print() requires this */
+
+ buf[21] = '\0';
+
+ print (0, 0, buf);
+ print (1, 0, buf);
+}
+
+void
+TranzportControlProtocol::show_bbt (nframes_t where)
+{
+ if (where != last_where) {
+ char buf[16];
+ BBT_Time bbt;
+
+ // When recording or playing back < 1.0 speed do 1 or 2
+ // FIXME - clean up state machine & break up logic
+ // this has to co-operate with the mini-meter and
+ // this is NOT the right way.
+
+ session->tempo_map().bbt_time (where, bbt);
+ last_bars = bbt.bars;
+ last_beats = bbt.beats;
+ last_ticks = bbt.ticks;
+ last_where = where;
+
+ float speed = fabsf(session->transport_speed());
+
+ if (speed == 1.0) {
+ sprintf (buf, "%03" PRIu32 "%1" PRIu32, bbt.bars,bbt.beats); // switch to hex one day
+ print (1, 16, buf);
+ }
+
+ if (speed == 0.0) {
+ sprintf (buf, "%03" PRIu32 "|%1" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
+ print (1, 10, buf);
+ }
+
+ if (speed > 0.0 && (speed < 1.0)) {
+ sprintf (buf, "%03" PRIu32 "|%1" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
+ print (1, 10, buf);
+ }
+
+ if (speed > 1.0 && (speed < 2.0)) {
+ sprintf (buf, "%03" PRIu32 "|%1" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
+ print (1, 10, buf);
+ }
+
+ if (speed >= 2.0) {
+ sprintf (buf, "%03" PRIu32 "|%1" PRIu32 "|%02" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
+ print (1, 12, buf);
+ }
+
+ TempoMap::Metric m (session->tempo_map().metric_at (where));
+
+ // the lights stop working well at above 100 bpm so don't bother
+ if(m.tempo().beats_per_minute() < 101.0 && (speed > 0.0)) {
+
+ // something else can reset these, so we need to
+
+ lights_pending[LightRecord] = false;
+ lights_pending[LightAnysolo] = false;
+ switch(last_beats) {
+ case 1: if(last_ticks < 250 || last_ticks >= 0) lights_pending[LightRecord] = true; break;
+ default: if(last_ticks < 250) lights_pending[LightAnysolo] = true;
+ }
+ }
+ }
+}
+
+void
+TranzportControlProtocol::show_transport_time ()
+{
+ nframes_t where = session->transport_frame();
+ show_bbt(where);
+}
+
+void
+TranzportControlProtocol::show_smpte (nframes_t where)
+{
+ if ((where != last_where) || lcd_isdamaged(1,9,10)) {
+
+ char buf[5];
+ SMPTE::Time smpte;
+
+ session->smpte_time (where, smpte);
+
+ if (smpte.negative) {
+ sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
+ } else {
+ sprintf (buf, " %02" PRIu32 ":", smpte.hours);
+ }
+ print (1, 8, buf);
+
+ sprintf (buf, "%02" PRIu32 ":", smpte.minutes);
+ print (1, 12, buf);
+
+ sprintf (buf, "%02" PRIu32 ":", smpte.seconds);
+ print (1, 15, buf);
+
+ sprintf (buf, "%02" PRIu32, smpte.frames);
+ print_noretry (1, 18, buf);
+
+ last_where = where;
+ }
+}
+
+void
+TranzportControlProtocol::show_track_gain ()
+{
+// FIXME last_track gain has to become meter/track specific
+ if (route_table[0]) {
+ gain_t g = route_get_gain (0);
+ if ((g != last_track_gain) || lcd_isdamaged(0,12,8)) {
+ char buf[16];
+ snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
+ print (0, 12, buf);
+ last_track_gain = g;
+ }
+ } else {
+ print (0, 9, " ");
+ }
+}
diff --git a/libs/surfaces/tranzport/slider_gain.h b/libs/surfaces/tranzport/slider_gain.h
new file mode 100644
index 0000000000..1bb497178f
--- /dev/null
+++ b/libs/surfaces/tranzport/slider_gain.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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_slider_gain
+#define ardour_slider_gain
+
+static inline double
+gain_to_slider_position (ARDOUR::gain_t g)
+{
+ if (g == 0) return 0;
+ return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
+
+}
+
+static inline ARDOUR::gain_t
+slider_position_to_gain (double pos)
+{
+ /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
+ if (pos == 0.0) return 0;
+ return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
+}
+
+#endif
diff --git a/libs/surfaces/tranzport/state.cc b/libs/surfaces/tranzport/state.cc
new file mode 100644
index 0000000000..1cb55b4fc3
--- /dev/null
+++ b/libs/surfaces/tranzport/state.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <iostream>
+#include <algorithm>
+#include <cmath>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <ardour/route.h>
+#include <ardour/audio_track.h>
+#include <ardour/session.h>
+#include <ardour/location.h>
+#include <ardour/dB.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+#include "tranzport_control_protocol.h"
+
+
+// FIXME: How to handle multiple tranzports in a system?
+
+XMLNode&
+TranzportControlProtocol::get_state ()
+{
+ XMLNode* node = new XMLNode (X_("Protocol"));
+ node->add_property (X_("name"), _name);
+ return *node;
+}
+
+int
+TranzportControlProtocol::set_state (const XMLNode& node)
+{
+ cout << "TranzportControlProtocol::set_state: active " << _active << endl;
+ int retval = 0;
+
+// I think I want to make these strings rather than numbers
+#if 0
+ // fetch current display mode
+ if ( node.property( X_("display_mode") ) != 0 )
+ {
+ string display = node.property( X_("display_mode") )->value();
+ try
+ {
+ set_active( true );
+ int32_t new_display = atoi( display.c_str() );
+ if ( display_mode != new_display ) display_mode = (DisplayMode)new_display;
+ }
+ catch ( exception & e )
+ {
+ cout << "exception in TranzportControlProtocol::set_state: " << e.what() << endl;
+ return -1;
+ }
+ }
+
+ if ( node.property( X_("wheel_mode") ) != 0 )
+ {
+ string wheel = node.property( X_("wheel_mode") )->value();
+ try
+ {
+ int32_t new_wheel = atoi( wheel.c_str() );
+ if ( wheel_mode != new_wheel ) wheel_mode = (WheelMode) new_wheel;
+ }
+ catch ( exception & e )
+ {
+ cout << "exception in TranzportControlProtocol::set_state: " << e.what() << endl;
+ return -1;
+ }
+ }
+
+ // fetch current bling mode
+ if ( node.property( X_("bling") ) != 0 )
+ {
+ string bling = node.property( X_("bling_mode") )->value();
+ try
+ {
+ int32_t new_bling = atoi( bling.c_str() );
+ if ( bling_mode != new_bling ) bling_mode = (BlingMode) new_bling;
+ }
+ catch ( exception & e )
+ {
+ cout << "exception in TranzportControlProtocol::set_state: " << e.what() << endl;
+ return -1;
+ }
+ }
+#endif
+
+ return retval;
+
+}
+
+// These are intended for the day we have more options for tranzport modes
+// And perhaps we could load up sessions this way, too
+
+int
+TranzportControlProtocol::save (char *name)
+{
+ // Presently unimplemented
+ return 0;
+}
+
+int
+TranzportControlProtocol::load (char *name)
+{
+ // Presently unimplemented
+ return 0;
+}
+
+int
+TranzportControlProtocol::save_config (char *name)
+{
+ // Presently unimplemented
+ return 0;
+}
+
+int
+TranzportControlProtocol::load_config (char *name)
+{
+ // Presently unimplemented
+ return 0;
+}
diff --git a/libs/surfaces/tranzport/tranzport_base.h b/libs/surfaces/tranzport/tranzport_base.h
new file mode 100644
index 0000000000..510f24fdfe
--- /dev/null
+++ b/libs/surfaces/tranzport/tranzport_base.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* This header file is basically where all the tranzport debuggable options go.
+ Try to only check it in with minimal debugging enabled so production
+ systems don't have to fiddle with it. */
+
+/* Design notes: The tranzport is a unique device, basically a
+ 20x2 character lcd gui with (almost) 22 shift keys and 8 blinking lights.
+
+ As such it has several unique constraints. In the libusb driver,
+ the device exerts flow control
+ by having a usb write fail. It is pointless to retry madly at that point,
+ the device is busy, and it's not going to become unbusy very quickly.
+
+ So writes need to be either "mandatory" or "unreliable", and therein
+ lies the rub, as the kernel can also drop writes, and missing an
+ interrupt in userspace is also generally bad.
+
+ However, the kernel driver retries writes for you and also buffers and
+ compresses incoming wheel events - it will rarely, if ever, drop data.
+
+ A more complex surface might have hundreds of lights and several displays.
+
+ mike@taht.net
+*/
+
+#ifndef ardour_tranzport_base
+#define ardour_tranzport_base
+
+#define DEFAULT_USB_TIMEOUT 10
+#define MAX_RETRY 1
+#define MAX_TRANZPORT_INFLIGHT 4
+#define DEBUG_TRANZPORT 0
+#define TRANZPORT_THREADS 0
+
+#ifndef HAVE_TRANZPORT_KERNEL_DRIVER
+#define HAVE_TRANZPORT_KERNEL_DRIVER 0
+#endif
+
+#ifndef HAVE_TRANZPORT_MIDI_DRIVER
+#define HAVE_TRANZPORT_MIDI_DRIVER 0
+#endif
+
+// for now, this is what the device is called
+#define TRANZPORT_DEVICE "/dev/tranzport0"
+
+#if DEBUG_TRANZPORT > 0
+#define DEBUG_TRANZPORT_SCREEN 10
+#define DEBUG_TRANZPORT_BITS 10
+#define DEBUG_TRANZPORT_LIGHTS 10
+#define DEBUG_TRANZPORT_STATE 10
+#else
+#define DEBUG_TRANZPORT 0
+#define DEBUG_TRANZPORT_BITS 0
+#define DEBUG_TRANZPORT_SCREEN 0
+#define DEBUG_TRANZPORT_LIGHTS 0
+#define DEBUG_TRANZPORT_STATE 0
+#endif
+#endif /* ardour_tranzport_base */
+
diff --git a/libs/surfaces/tranzport/tranzport_common.h b/libs/surfaces/tranzport/tranzport_common.h
new file mode 100644
index 0000000000..06b07bd62a
--- /dev/null
+++ b/libs/surfaces/tranzport/tranzport_common.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* The most common header files that the tranzport uses */
+
+#ifndef ardour_tranzport_common
+#define ardour_tranzport_common
+#include <iostream>
+#include <algorithm>
+#include <cmath>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <pbd/pthread_utils.h>
+
+#include <ardour/route.h>
+#include <ardour/audio_track.h>
+#include <ardour/session.h>
+#include <ardour/tempo.h>
+#include <ardour/location.h>
+#include <ardour/dB.h>
+
+#endif /* ardour_tranzport_common */
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h
index f13e4a3a44..929cca3e2b 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.h
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.h
@@ -1,22 +1,46 @@
+/*
+ Copyright (C) 2006 Paul Davis
+ Copyright (C) 2007 Mike Taht
+
+ 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_tranzport_control_protocol_h
#define ardour_tranzport_control_protocol_h
-#include <vector>
+#include "tranzport_base.h"
+#include <vector>
+#include <bitset>
#include <sys/time.h>
#include <pthread.h>
+
+#if !HAVE_TRANZPORT_KERNEL_DRIVER
#include <usb.h>
+#endif
#include <glibmm/thread.h>
-
#include <ardour/types.h>
#include <control_protocol/control_protocol.h>
class TranzportControlProtocol : public ARDOUR::ControlProtocol
{
- public:
+public:
TranzportControlProtocol (ARDOUR::Session&);
virtual ~TranzportControlProtocol();
@@ -27,14 +51,19 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
XMLNode& get_state ();
int set_state (const XMLNode&);
- private:
+private:
static const int VENDORID = 0x165b;
static const int PRODUCTID = 0x8101;
static const int READ_ENDPOINT = 0x81;
static const int WRITE_ENDPOINT = 0x02;
const static int STATUS_OFFLINE = 0xff;
const static int STATUS_ONLINE = 0x01;
- const static uint8_t WheelDirectionThreshold = 0x3f;
+ const static int STATUS_OK = 0x00;
+
+ const static int LIGHTS = 7;
+ const static int ROWS = 2;
+ const static int COLUMNS = 20;
+ const static uint8_t WheelDirectionThreshold = 0x7f;
enum LightID {
LightRecord = 0,
@@ -67,7 +96,8 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
ButtonStop = 0x00010000,
ButtonPlay = 0x00100000,
ButtonRecord = 0x00000100,
- ButtonShift = 0x08000000
+ ButtonShift = 0x08000000,
+ ButtonFootswitch = 0x00001000
};
enum WheelShiftMode {
@@ -86,13 +116,13 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
// FIXME - look at gtk2_ardour for snap settings
enum WheelIncrement {
- WheelIncrSlave,
- WheelIncrScreen,
- WheelIncrSample,
- WheelIncrBeat,
- WheelIncrBar,
- WheelIncrSecond,
- WheelIncrMinute
+ WheelIncrSlave,
+ WheelIncrScreen,
+ WheelIncrSample,
+ WheelIncrBeat,
+ WheelIncrBar,
+ WheelIncrSecond,
+ WheelIncrMinute
};
enum DisplayMode {
@@ -111,37 +141,55 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
BlingRotating,
BlingPairs,
BlingRows,
- BlingFlashAll
+ BlingFlashAll,
+ BlingEnter,
+ BlingExit
};
pthread_t thread;
+#if HAVE_TRANZPORT_KERNEL_DRIVER
+ int udev;
+#else
+ usb_dev_handle* udev;
+#endif
+
+#if TRANZPORT_THREADS
+ pthread_t thread_read;
+#endif
+ int last_read_error;
+
uint32_t buttonmask;
uint32_t timeout;
uint32_t inflight;
+ uint32_t current_track_id;
+#if TRANZPORT_THREADS
+ pthread_t thread_write;
+#endif
+ int last_write_error;
uint8_t _datawheel;
uint8_t _device_status;
- uint32_t current_track_id;
WheelMode wheel_mode;
WheelShiftMode wheel_shift_mode;
DisplayMode display_mode;
BlingMode bling_mode;
WheelIncrement wheel_increment;
- usb_dev_handle* udev;
ARDOUR::gain_t gain_fraction;
Glib::Mutex update_lock;
- bool screen_invalid[2][20];
- char screen_current[2][20];
- char screen_pending[2][20];
- char screen_flash[2][20];
+ std::bitset<ROWS*COLUMNS> screen_invalid;
+ char screen_current[ROWS][COLUMNS];
+ char screen_pending[ROWS][COLUMNS];
+ char screen_flash[ROWS][COLUMNS];
- bool lights_invalid[7];
- bool lights_current[7];
- bool lights_pending[7];
- bool lights_flash[7];
+ std::bitset<LIGHTS> lights_invalid;
+ std::bitset<LIGHTS> lights_current;
+ std::bitset<LIGHTS> lights_pending;
+ std::bitset<LIGHTS> lights_flash;
+ int32_t last_notify;
+ char last_notify_msg[COLUMNS+1];
uint32_t last_bars;
uint32_t last_beats;
uint32_t last_ticks;
@@ -151,7 +199,7 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
uint32_t last_mins;
uint32_t last_secs;
uint32_t last_frames;
- nframes_t last_where;
+ nframes_t last_where;
ARDOUR::gain_t last_track_gain;
uint32_t last_meter_fill;
struct timeval last_wheel_motion;
@@ -164,16 +212,25 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
int write (uint8_t* cmd, uint32_t timeout_override = 0);
int write_noretry (uint8_t* cmd, uint32_t timeout_override = 0);
int close ();
- int save(char *name = "default");
- int load(char *name = "default");
- void print (int row, int col, const char* text);
+ int save_config(char *name = "default");
+ int load_config(char *name = "default");
+ int save(char *name);
+ int load(char *name);
+ void print (int row, int col, const char* text);
void print_noretry (int row, int col, const char* text);
+ void notify(const char *msg);
+#if HAVE_TRANZPORT_KERNEL_DRIVER
+ int rtpriority_set(int priority = 3); // we don't need serious rt privs anymore
+#else
int rtpriority_set(int priority = 52);
+#endif
int rtpriority_unset(int priority = 0);
+ // I hate changing the api to do either but until I have clean io class what can you do?
+#if !HAVE_TRANZPORT_KERNEL_DRIVER
int open_core (struct usb_device*);
-
+#endif
static void* _monitor_work (void* arg);
void* monitor_work ();
@@ -191,6 +248,7 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
int screen_flush();
void screen_clear();
// bool screen_isuptodate(); // think on this -
+ int screen_show_bling();
// Commands to write to the lcd
@@ -198,8 +256,8 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
bool lcd_damage();
bool lcd_isdamaged();
- bool lcd_damage(int row, int col = 0, int length = 20);
- bool lcd_isdamaged(int row, int col = 0, int length = 20);
+ bool lcd_damage(int row, int col = 0, int length = COLUMNS);
+ bool lcd_isdamaged(int row, int col = 0, int length = COLUMNS);
int lcd_flush();
int lcd_write(uint8_t* cmd, uint32_t timeout_override = 0); // pedantic alias for write
@@ -240,6 +298,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
void enter_recording_mode();
void enter_bling_mode();
+ void next_marker (); // basicui doesn't give me enough info
+ void prev_marker ();
+
void next_display_mode ();
void normal_update ();
@@ -252,6 +313,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
void show_gain ();
void show_pan ();
void show_meter ();
+ void show_mini_meter ();
+ void show_bling();
+ void show_notify();
void datawheel ();
void scrub ();
@@ -311,8 +375,10 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
void button_event_play_release (bool shifted);
void button_event_record_press (bool shifted);
void button_event_record_release (bool shifted);
+ void button_event_footswitch_press(bool shifted);
+ void button_event_footswitch_release (bool shifted);
- // new api
+ // new api - still thinking about it
void button_event_mute (bool pressed, bool shifted);
};
diff --git a/libs/surfaces/tranzport/view_automation.cc b/libs/surfaces/tranzport/view_automation.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_automation.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_bigmeter.cc b/libs/surfaces/tranzport/view_bigmeter.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_bigmeter.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_bling.cc b/libs/surfaces/tranzport/view_bling.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_bling.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_bus.cc b/libs/surfaces/tranzport/view_bus.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_bus.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_config.cc b/libs/surfaces/tranzport/view_config.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_config.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_layer.cc b/libs/surfaces/tranzport/view_layer.cc
new file mode 100644
index 0000000000..8de9e3ad14
--- /dev/null
+++ b/libs/surfaces/tranzport/view_layer.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+/* ultimately this view will let you: rotate layers (takes) on the currently selected track/region, do cross fades, and the like */
diff --git a/libs/surfaces/tranzport/view_loop.cc b/libs/surfaces/tranzport/view_loop.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_loop.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_manymeter.cc b/libs/surfaces/tranzport/view_manymeter.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_manymeter.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_marker.cc b/libs/surfaces/tranzport/view_marker.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_marker.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_master.cc b/libs/surfaces/tranzport/view_master.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_master.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_plugins.cc b/libs/surfaces/tranzport/view_plugins.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_plugins.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_std.cc b/libs/surfaces/tranzport/view_std.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_std.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_tempo.cc b/libs/surfaces/tranzport/view_tempo.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_tempo.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/view_tuner.cc b/libs/surfaces/tranzport/view_tuner.cc
new file mode 100644
index 0000000000..4c0b18acf0
--- /dev/null
+++ b/libs/surfaces/tranzport/view_tuner.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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.
+ *
+ * */
+
+
diff --git a/libs/surfaces/tranzport/wheel.cc b/libs/surfaces/tranzport/wheel.cc
new file mode 100644
index 0000000000..bc9683e6d7
--- /dev/null
+++ b/libs/surfaces/tranzport/wheel.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <iostream>
+#include <algorithm>
+#include <cmath>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <ardour/route.h>
+#include <ardour/audio_track.h>
+#include <ardour/session.h>
+#include <ardour/location.h>
+#include <ardour/dB.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
+BaseUI::RequestType Print = BaseUI::new_request_type ();
+BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
+
+
+#include <tranzport_control_protocol.h>
+
+void
+TranzportControlProtocol::datawheel ()
+{
+ if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
+
+ /* track scrolling */
+
+ if (_datawheel < WheelDirectionThreshold) {
+ next_track ();
+ } else {
+ prev_track ();
+ }
+
+ timerclear (&last_wheel_motion);
+
+ } else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
+
+ if (_datawheel < WheelDirectionThreshold) {
+ next_marker ();
+ } else {
+ prev_marker ();
+ }
+
+ timerclear (&last_wheel_motion);
+
+ } else if (buttonmask & ButtonShift) {
+
+ /* parameter control */
+
+ if (route_table[0]) {
+ switch (wheel_shift_mode) {
+ case WheelShiftGain:
+ if (_datawheel < WheelDirectionThreshold) {
+ step_gain_up ();
+ } else {
+ step_gain_down ();
+ }
+ break;
+ case WheelShiftPan:
+ if (_datawheel < WheelDirectionThreshold) {
+ step_pan_right ();
+ } else {
+ step_pan_left ();
+ }
+ break;
+
+ case WheelShiftMarker:
+ break;
+
+ case WheelShiftMaster:
+ break;
+
+ }
+ }
+
+ timerclear (&last_wheel_motion);
+
+ } else {
+
+ switch (wheel_mode) {
+ case WheelTimeline:
+ scroll ();
+ break;
+
+ case WheelScrub:
+ scrub ();
+ break;
+
+ case WheelShuttle:
+ shuttle ();
+ break;
+ }
+ }
+}
+
+void
+TranzportControlProtocol::scroll ()
+{
+ float m = 1.0;
+ if (_datawheel < WheelDirectionThreshold) {
+ m = 1.0;
+ } else {
+ m = -1.0;
+ }
+ switch(wheel_increment) {
+ case WheelIncrScreen: ScrollTimeline (0.2*m); break;
+ case WheelIncrSlave:
+ case WheelIncrSample:
+ case WheelIncrBeat:
+ case WheelIncrBar:
+ case WheelIncrSecond:
+ case WheelIncrMinute:
+ default: break; // other modes unimplemented as yet
+ }
+}
+
+void
+TranzportControlProtocol::scrub ()
+{
+ float speed;
+ struct timeval now;
+ struct timeval delta;
+ int dir;
+
+ gettimeofday (&now, 0);
+
+ if (_datawheel < WheelDirectionThreshold) {
+ dir = 1;
+ } else {
+ dir = -1;
+ }
+
+ if (dir != last_wheel_dir) {
+ /* changed direction, start over */
+ speed = 0.1f;
+ } else {
+ if (timerisset (&last_wheel_motion)) {
+
+ timersub (&now, &last_wheel_motion, &delta);
+
+ /* 10 clicks per second => speed == 1.0 */
+
+ speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
+
+ } else {
+
+ /* start at half-speed and see where we go from there */
+
+ speed = 0.5f;
+ }
+ }
+
+ last_wheel_motion = now;
+ last_wheel_dir = dir;
+
+ set_transport_speed (speed * dir);
+}
+
+void
+TranzportControlProtocol::shuttle ()
+{
+ if (_datawheel < WheelDirectionThreshold) {
+ if (session->transport_speed() < 0) {
+ session->request_transport_speed (1.0);
+ } else {
+ session->request_transport_speed (session->transport_speed() + 0.1);
+ }
+ } else {
+ if (session->transport_speed() > 0) {
+ session->request_transport_speed (-1.0);
+ } else {
+ session->request_transport_speed (session->transport_speed() - 0.1);
+ }
+ }
+}
diff --git a/libs/surfaces/tranzport/wheel_modes.cc b/libs/surfaces/tranzport/wheel_modes.cc
new file mode 100644
index 0000000000..06b3ae03b3
--- /dev/null
+++ b/libs/surfaces/tranzport/wheel_modes.cc
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * 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 <iostream>
+#include <algorithm>
+#include <cmath>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <float.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#if HAVE_TRANZPORT_KERNEL_DRIVER
+#include <fcntl.h>
+#include <poll.h>
+#endif
+
+#include <pbd/pthread_utils.h>
+
+#include <ardour/route.h>
+#include <ardour/audio_track.h>
+#include <ardour/session.h>
+#include <ardour/tempo.h>
+#include <ardour/location.h>
+#include <ardour/dB.h>
+
+#include <tranzport_control_protocol.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+void
+TranzportControlProtocol::next_wheel_shift_mode ()
+{
+switch (wheel_shift_mode) {
+ case WheelShiftGain:
+ wheel_shift_mode = WheelShiftPan;
+ break;
+ case WheelShiftPan:
+ wheel_shift_mode = WheelShiftMaster;
+ break;
+ case WheelShiftMaster:
+ wheel_shift_mode = WheelShiftGain;
+ break;
+ case WheelShiftMarker: // Not done yet, disabled
+ wheel_shift_mode = WheelShiftGain;
+ break;
+ }
+
+ show_wheel_mode ();
+}
+
+void
+TranzportControlProtocol::next_wheel_mode ()
+{
+ switch (wheel_mode) {
+ case WheelTimeline:
+ wheel_mode = WheelScrub;
+ break;
+ case WheelScrub:
+ wheel_mode = WheelShuttle;
+ break;
+ case WheelShuttle:
+ wheel_mode = WheelTimeline;
+ }
+
+ show_wheel_mode ();
+}
+
+void
+TranzportControlProtocol::show_wheel_mode ()
+{
+ string text;
+
+ // if(session->transport_speed() != 0) {
+ // if session-transport_speed() < 1.0) show_big_bar/beat
+ // if ? greater. dont
+
+ if(session->transport_speed() != 0) {
+ show_mini_meter();
+ } else {
+
+ switch (wheel_mode) {
+ case WheelTimeline:
+ text = "Time";
+ break;
+ case WheelScrub:
+ text = "Scrb";
+ break;
+ case WheelShuttle:
+ text = "Shtl";
+ break;
+ }
+
+ switch (wheel_shift_mode) {
+ case WheelShiftGain:
+ text += ":Gain";
+ break;
+
+ case WheelShiftPan:
+ text += ":Pan ";
+ break;
+
+ case WheelShiftMaster:
+ text += ":Mstr";
+ break;
+
+ case WheelShiftMarker:
+ text += ":Mrkr";
+ break;
+ }
+
+ print (1, 0, text.c_str());
+ }
+}