From ceac394c2133d44e81db2eb633ff54a9ad6ce7c5 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 10 Nov 2005 05:52:11 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r3865, which included commits to RCS files with non-trunk default branches. svn path=/trunk/extensions/gripd/; revision=3866 --- .xvpics/joystickA.xpm | Bin 0 -> 337 bytes .xvpics/midiA.xpm | Bin 0 -> 337 bytes README.txt | 181 ++ connect.xpm | 27 + connectX.xpm | 24 + examples/clickme.jpg | Bin 0 -> 2798 bytes examples/fmlogo.gif | Bin 0 -> 6459 bytes examples/fmsynth.gpd | 442 +++++ examples/gripd.gpd | 380 +++++ examples/gripd.pd | 73 + examples/gripdExamples.pd | 247 +++ examples/gripdFM.pd | 135 ++ examples/poof.jpg | Bin 0 -> 2065 bytes examples/scale.gif | Bin 0 -> 2240 bytes examples/scale2.gif | Bin 0 -> 2296 bytes examples/screw.gif | Bin 0 -> 1181 bytes gripd | 42 + gripd.opt | 2 + gripd.py | 43 + gripd.spec | 16 + gripdControls.py | 1675 ++++++++++++++++++ gripdFunctions.py | 191 +++ gripdMain.py | 2337 ++++++++++++++++++++++++++ icon.pic | Bin 0 -> 3774 bytes joystick.xpm | 68 + joystickA.xpm | 45 + joystickX.xpm | 57 + log.txt | 0 midi.xpm | 24 + midiA.xpm | 24 + midiX.xpm | 26 + src/Makefile.Linux | 48 + src/Makefile.NT | 86 + src/Makefile.midiioLibrary.ALSA | 205 +++ src/Makefile.midiioLibrary.NT | 462 +++++ src/Makefile.midiioLibrary.OSS | 205 +++ src/gripd.c | 1031 ++++++++++++ src/gripd.h | 227 +++ src/joystick.c | 296 ++++ src/joystick_wrap.c | 692 ++++++++ src/makefile | 44 + src/midi.cpp | 146 ++ src/midi_wrap.c | 723 ++++++++ src/midiio/include/Array.cpp | 378 +++++ src/midiio/include/Array.h | 67 + src/midiio/include/CircularBuffer.cpp | 291 ++++ src/midiio/include/CircularBuffer.h | 66 + src/midiio/include/Collection.cpp | 355 ++++ src/midiio/include/Collection.h | 70 + src/midiio/include/FileIO.h | 148 ++ src/midiio/include/MidiFile.h | 108 ++ src/midiio/include/MidiFileWrite.h | 61 + src/midiio/include/MidiIO.h | 58 + src/midiio/include/MidiInPort.h | 98 ++ src/midiio/include/MidiInPort_alsa.h | 107 ++ src/midiio/include/MidiInPort_alsa05.h | 107 ++ src/midiio/include/MidiInPort_linux.h | 94 ++ src/midiio/include/MidiInPort_oss.h | 105 ++ src/midiio/include/MidiInPort_unsupported.h | 89 + src/midiio/include/MidiInPort_visual.h | 114 ++ src/midiio/include/MidiInput.h | 53 + src/midiio/include/MidiMessage.h | 78 + src/midiio/include/MidiOutPort.h | 92 + src/midiio/include/MidiOutPort_alsa.h | 79 + src/midiio/include/MidiOutPort_linux.h | 80 + src/midiio/include/MidiOutPort_oss.h | 75 + src/midiio/include/MidiOutPort_unsupported.h | 71 + src/midiio/include/MidiOutPort_visual.h | 75 + src/midiio/include/MidiOutput.h | 140 ++ src/midiio/include/MidiPort.h | 49 + src/midiio/include/Options.h | 106 ++ src/midiio/include/Options_private.h | 73 + src/midiio/include/Sequencer_alsa.h | 139 ++ src/midiio/include/Sequencer_oss.h | 92 + src/midiio/include/SigTimer.h | 104 ++ src/midiio/include/Voice.h | 70 + src/midiio/include/gminstruments.h | 251 +++ src/midiio/include/midichannels.h | 42 + src/midiio/include/mididefines.h | 34 + src/midiio/include/midiiolib.h | 57 + src/midiio/include/notenames.h | 219 +++ src/midiio/include/sigConfiguration.h | 100 ++ src/midiio/src/FileIO.cpp | 761 +++++++++ src/midiio/src/MidiFile.cpp | 1200 +++++++++++++ src/midiio/src/MidiFileWrite.cpp | 259 +++ src/midiio/src/MidiIO.cpp | 283 ++++ src/midiio/src/MidiInPort_alsa.cpp | 1038 ++++++++++++ src/midiio/src/MidiInPort_alsa05.cpp | 995 +++++++++++ src/midiio/src/MidiInPort_linux.cpp | 491 ++++++ src/midiio/src/MidiInPort_oss.cpp | 1036 ++++++++++++ src/midiio/src/MidiInPort_unsupported.cpp | 487 ++++++ src/midiio/src/MidiInPort_visual.cpp | 1267 ++++++++++++++ src/midiio/src/MidiInput.cpp | 224 +++ src/midiio/src/MidiMessage.cpp | 406 +++++ src/midiio/src/MidiOutPort_alsa.cpp | 469 ++++++ src/midiio/src/MidiOutPort_linux.cpp | 381 +++++ src/midiio/src/MidiOutPort_oss.cpp | 462 +++++ src/midiio/src/MidiOutPort_unsupported.cpp | 402 +++++ src/midiio/src/MidiOutPort_visual.cpp | 532 ++++++ src/midiio/src/MidiOutput.cpp | 1082 ++++++++++++ src/midiio/src/MidiPort.cpp | 189 +++ src/midiio/src/Options.cpp | 887 ++++++++++ src/midiio/src/Options_private.cpp | 358 ++++ src/midiio/src/Sequencer_alsa.cpp | 643 +++++++ src/midiio/src/Sequencer_alsa05.cpp | 518 ++++++ src/midiio/src/Sequencer_oss.cpp | 809 +++++++++ src/midiio/src/SigTimer.cpp | 498 ++++++ src/midiio/src/Voice.cpp | 334 ++++ 108 files changed, 30630 insertions(+) create mode 100644 .xvpics/joystickA.xpm create mode 100644 .xvpics/midiA.xpm create mode 100644 README.txt create mode 100644 connect.xpm create mode 100644 connectX.xpm create mode 100644 examples/clickme.jpg create mode 100644 examples/fmlogo.gif create mode 100644 examples/fmsynth.gpd create mode 100644 examples/gripd.gpd create mode 100644 examples/gripd.pd create mode 100644 examples/gripdExamples.pd create mode 100644 examples/gripdFM.pd create mode 100644 examples/poof.jpg create mode 100644 examples/scale.gif create mode 100644 examples/scale2.gif create mode 100644 examples/screw.gif create mode 100755 gripd create mode 100644 gripd.opt create mode 100644 gripd.py create mode 100644 gripd.spec create mode 100644 gripdControls.py create mode 100644 gripdFunctions.py create mode 100644 gripdMain.py create mode 100644 icon.pic create mode 100644 joystick.xpm create mode 100644 joystickA.xpm create mode 100644 joystickX.xpm create mode 100644 log.txt create mode 100644 midi.xpm create mode 100644 midiA.xpm create mode 100644 midiX.xpm create mode 100644 src/Makefile.Linux create mode 100644 src/Makefile.NT create mode 100644 src/Makefile.midiioLibrary.ALSA create mode 100644 src/Makefile.midiioLibrary.NT create mode 100644 src/Makefile.midiioLibrary.OSS create mode 100644 src/gripd.c create mode 100644 src/gripd.h create mode 100644 src/joystick.c create mode 100644 src/joystick_wrap.c create mode 100644 src/makefile create mode 100644 src/midi.cpp create mode 100644 src/midi_wrap.c create mode 100644 src/midiio/include/Array.cpp create mode 100644 src/midiio/include/Array.h create mode 100644 src/midiio/include/CircularBuffer.cpp create mode 100644 src/midiio/include/CircularBuffer.h create mode 100644 src/midiio/include/Collection.cpp create mode 100644 src/midiio/include/Collection.h create mode 100644 src/midiio/include/FileIO.h create mode 100644 src/midiio/include/MidiFile.h create mode 100644 src/midiio/include/MidiFileWrite.h create mode 100644 src/midiio/include/MidiIO.h create mode 100644 src/midiio/include/MidiInPort.h create mode 100644 src/midiio/include/MidiInPort_alsa.h create mode 100644 src/midiio/include/MidiInPort_alsa05.h create mode 100644 src/midiio/include/MidiInPort_linux.h create mode 100644 src/midiio/include/MidiInPort_oss.h create mode 100644 src/midiio/include/MidiInPort_unsupported.h create mode 100644 src/midiio/include/MidiInPort_visual.h create mode 100644 src/midiio/include/MidiInput.h create mode 100644 src/midiio/include/MidiMessage.h create mode 100644 src/midiio/include/MidiOutPort.h create mode 100644 src/midiio/include/MidiOutPort_alsa.h create mode 100644 src/midiio/include/MidiOutPort_linux.h create mode 100644 src/midiio/include/MidiOutPort_oss.h create mode 100644 src/midiio/include/MidiOutPort_unsupported.h create mode 100644 src/midiio/include/MidiOutPort_visual.h create mode 100644 src/midiio/include/MidiOutput.h create mode 100644 src/midiio/include/MidiPort.h create mode 100644 src/midiio/include/Options.h create mode 100644 src/midiio/include/Options_private.h create mode 100644 src/midiio/include/Sequencer_alsa.h create mode 100644 src/midiio/include/Sequencer_oss.h create mode 100644 src/midiio/include/SigTimer.h create mode 100644 src/midiio/include/Voice.h create mode 100644 src/midiio/include/gminstruments.h create mode 100644 src/midiio/include/midichannels.h create mode 100644 src/midiio/include/mididefines.h create mode 100644 src/midiio/include/midiiolib.h create mode 100644 src/midiio/include/notenames.h create mode 100644 src/midiio/include/sigConfiguration.h create mode 100644 src/midiio/src/FileIO.cpp create mode 100644 src/midiio/src/MidiFile.cpp create mode 100644 src/midiio/src/MidiFileWrite.cpp create mode 100644 src/midiio/src/MidiIO.cpp create mode 100644 src/midiio/src/MidiInPort_alsa.cpp create mode 100644 src/midiio/src/MidiInPort_alsa05.cpp create mode 100644 src/midiio/src/MidiInPort_linux.cpp create mode 100644 src/midiio/src/MidiInPort_oss.cpp create mode 100644 src/midiio/src/MidiInPort_unsupported.cpp create mode 100644 src/midiio/src/MidiInPort_visual.cpp create mode 100644 src/midiio/src/MidiInput.cpp create mode 100644 src/midiio/src/MidiMessage.cpp create mode 100644 src/midiio/src/MidiOutPort_alsa.cpp create mode 100644 src/midiio/src/MidiOutPort_linux.cpp create mode 100644 src/midiio/src/MidiOutPort_oss.cpp create mode 100644 src/midiio/src/MidiOutPort_unsupported.cpp create mode 100644 src/midiio/src/MidiOutPort_visual.cpp create mode 100644 src/midiio/src/MidiOutput.cpp create mode 100644 src/midiio/src/MidiPort.cpp create mode 100644 src/midiio/src/Options.cpp create mode 100644 src/midiio/src/Options_private.cpp create mode 100644 src/midiio/src/Sequencer_alsa.cpp create mode 100644 src/midiio/src/Sequencer_alsa05.cpp create mode 100644 src/midiio/src/Sequencer_oss.cpp create mode 100644 src/midiio/src/SigTimer.cpp create mode 100644 src/midiio/src/Voice.cpp diff --git a/.xvpics/joystickA.xpm b/.xvpics/joystickA.xpm new file mode 100644 index 0000000..4b12dd6 Binary files /dev/null and b/.xvpics/joystickA.xpm differ diff --git a/.xvpics/midiA.xpm b/.xvpics/midiA.xpm new file mode 100644 index 0000000..9865cba Binary files /dev/null and b/.xvpics/midiA.xpm differ diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..d00f577 --- /dev/null +++ b/README.txt @@ -0,0 +1,181 @@ +GrIPD: Graphical Interface for Pure Data +---------------------------------------- + +v0.1.1 + +-What is GrIPD- +GrIPD is a cross-platform extension to Miller Puckette's Pure Data +software that allows the one to design custom graphical user +interfaces for Pd patches. GrIPD is not a replacement for the Pd +Tcl/Tk GUI, but instead is intended to allow one to create a front end +to a Pd patch. The concept is to create your PD patch normally and +then your GUI using GrIPD. You can then lauch Pd using the -nogui +command line argument (although this is certainly not necessary) so +only your custom front end will be displayed. GrIPD, itself, consists +of two parts: the "gripd" Pd object and an external GUI +window/editor. The Pd object was written in C and the external GUI was +written in Python using the wxWindows. GrIPD is released under the +GNU General Public License. + + +-How GrIPD works- +The two parts of GrIPD communicate via TCP/IP sockets so they can run +on one machine or on separate machines over a network; so, for +example, the GUI could be on a laptop on stage controlling or +displaying info from the Pd audio engine in the house next to the +mixer. The communication works through Pd's implimentation of +"send" and "receive" objects. Basically, each GrIPD control object has +a send and receive symbol associated with it. + + +-Supported platforms- +GrIPD is currently available for Linux/GTK+ and MS Windows +platforms. It may work on other Unix's, but as of yet it has not been +tested. Since wxPython and C are both highly portable, most of GrIPD +is as well. The only issues should be the C socket and multi-process +code. + + +-Requirements- + For Win32: + * Pd + For Linux: + * Pd + * GTK+ + + To compile under Win32: + * Python (v2.2 or later) + * wxPython- wxWindows for Python (v2.4.0 or later) + * a C/C++ compiler + * to make a stand-alone .exe file you'll also need + py2exe v0.3.1 (http://starship.python.net/crew/theller/py2exe/) + + To compile under Linux: + * Python (v2.2 or later) + * wxPython- wxWindows for Python (v2.4.0 or later) + * GTK+ and wxGTK + * C/C++ compiler + * to make a stand-alone binary executable you'll also need + Installer v5b4 (http://www.mcmillan-inc.com/install5_ann.html) + +All of the above are, of course, free. +For Windows: the package includes compiled binaries of the gripd.dll Pd object + and the gripd.exe GUI executeable. +For Linux: stand-alone binary packages are available for x86 the architecture + with either OSS or ALSA MIDI support. + + +-Installation- + +Windows: + 1) Unzip contents of gripd-*.zip to .\pd\gripd\ + 2) Put gripd.dll where Pd can find it + To compile from source + 1) In .\pd\gripd\src: + a) edit makefile + b) run: nmake gripd_nt + 2) gripd.exe is included, but to recompile run: + python gripdSetup.py py2exe -w -O2 --icon icon.pic + +Linux: + 1) Ungzip/untar contents of gripd-*.tar.gz to ./pd/gripd/ + 2) Put gripd.pd_linux where Pd can find it + To compile from source: + 2) In ./pd/gripd/src + a) edit makefile + b) run: make gripd_linux + 3) to build a stand-alone binary executable of the GrIPD GUI run: + python -OO Build.py gripd.spec (Build.py is part of Installer v5b4) + +Be sure to have gripd.dll or gripd.pd_linux in your Pd path + +-Using GrIPD- +To use GrIPD, launch Pd with the -lib gripd command line +argument, and put the gripd Pd object on your patch; it's scope will be +global throughout all canvases. Then send it an "open " message to launch the GUI (gripd.exe or gripd.py). +You can also send a "open_locked " message which will open the +GUI in locked mode. This will prevent any changes from being made to +the GUI itself. + +You may need to set the path to gripd.py or gripd.exe by sending a +"set_path " message to the gripd Pd object. For Windows users not using +gripd.exe, you may also have to set the path to python.exe by sending a +"set_python_path " message. + +You may also send a "connect" message to set the gripd Pd object to wait for +an incomming connection and launch gripd.exe or gripd.py separately. + +If the path supplied to either an "open" message or a "set_path" message +is relative (i.e. begins with ./ or ../) they will be considered relative +to the directory containing the Pd executable file (pd.exe for Windows and +pd for Linux). This keeps behavior consistent no matter where Pd is launched +from. + +If the GUI is launched from PD, When the GUI window is closed you can re-open +it by sending the gripd Pd object a "show" message. You can also hide it by +sending the gripd Pd object a "hide" message. + +The GrIPD GUI itself has two modes: "Performance Mode" and "Edit +Mode". In "Edit Mode" you can add and remove controls using the +"Edit" menu, move them around by selecting them and dragging them by +their tag with the mouse or use the arrow keys (note: ctrl+ +will move controls a greater distance). You can edit a controls +properties by either selecting "Edit" from the "Edit" menu or +right-clicking the control's tab. In "Performance Mode" the controls +properties are locked and when activated (e.g. clicked, slid, checked, +etc.) they will send a message via their send symbol. Conversely, +they will receive messages sent within the Pd patch using their +receive symbol. Look at gripd.pd and gripdExamples.pd. + +GrIPD can forward MIDI input to Pd from up to two devices. To enable MIDI +function, select "Enable MIDI" from the "Configure" menu. GrIPD will send +note information via the "midinote" symbol where is either 0 or 1. +It will also send controller information via "midictl" and program change +information via "midipgm". + +GrIPD also allows for the use of up to two joysticks. To enable joystick +function, select "Enable Joystick" from the "Configure" menu. Joystick +axis and button information are sent to Pd with the send symbols +"joyaxis" and "joybutton" where is 0 or 1 and , is +0,1,... for the number of axes and buttons your joystick supports. For +example, to read from joystick 0 axis 0, put a "r joy0axis0" object in your +Pd patch. Axes will send integers in a range that will depend on your +joystick, and buttons will send 1 when depressed and 0 when released. + +GrIPD will also catch keystrokes and send the ASCII value to Pd while in +performance mode via a "keystroke" send symbol. Simply put a "r keystroke" +object in your Pd patch. + +Note about duplicating radio buttons: +When creating radio buttons, the first button created in a group is the +group marker. Duplicating any of the buttons in a group other than the +group marker button will add a button of the last group created. +Duplicating the group marker button will start a new group. + +Note about image paths: +When a path to an image is relative (i.e. begins with ./ or ../), it is +considered relative to the .gpd file containing the image. If no file +has been opened or saved, the path is considered relative to the directory +containing the gripd executable file (gripd.exe for Windows and gripd.py +for Linux). It is therefore recommended that all images used in a GUI be +placed in a directory directly lower than the directory containing the .gpd +file. For example if your .gpd file is in c:\pd-guis put all images in +c:\pd-guis\images. This will make distributing GUIs much simpler. + +Note about MIDI and joystick input: +If problems occur due to MIDI or joystick input, you can disable them by +editing gripd.opt + +-New in 0.1.1 +Added graph control +Added openpanel and savepanel +added MIDI and joystick activity blinking +Fixed zombie bug +Fixed multiple opens bug +Fixed checkbox and radio buttons bug +Fixed rectangle redrawing problem +Fixed selecting inside rectangle problem + +-Contact- +Drop me a line at jsarlo@ucsd.edu diff --git a/connect.xpm b/connect.xpm new file mode 100644 index 0000000..34f282c --- /dev/null +++ b/connect.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static char * connect_xpm[] = { +"21 16 8 1", +" c None", +". c #000000", +"+ c #00FF04", +"@ c #BFBFBF", +"# c #FEFEFE", +"$ c #00FEFE", +"% c #FF0000", +"& c #0000FE", +" .. ........ ", +" .+. .@@@@@@@@.", +" .....++. .@......@.", +" .+++++++..@.##$$.@.", +" .+...++. .@.#%&#.@.", +" .+. .+. .@.$#%#.@.", +" .+. .. .@......@.", +" ........ .@@@@@@@@.", +".@@@@@@@@. ........ ", +".@......@. .. .+. ", +".@.#&$$.@. .+. .+. ", +".@.#%&#.@. .++...+. ", +".@.$###.@..+++++++. ", +".@......@. .++..... ", +".@@@@@@@@. .+. ", +" ........ .. "}; diff --git a/connectX.xpm b/connectX.xpm new file mode 100644 index 0000000..fd4f27b --- /dev/null +++ b/connectX.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * connectX_xpm[] = { +"21 16 5 1", +" c None", +". c #000000", +"+ c #BFBFBF", +"@ c #FF0000", +"# c #3F3F3F", +" ........ ", +" .. .++++++++.", +" ....@@. .+......+.", +" .@@@@@. .+.####.+.", +" .@..@@. .+.####.+.", +" .@. .. .+.####.+.", +" .@. .+......+.", +" ........ .++++++++.", +".++++++++. ........ ", +".+......+. .@. ", +".+.####.+. .. .@. ", +".+.####.+. .@@..@. ", +".+.####.+. .@@@@@. ", +".+......+. .@@.... ", +".++++++++. .. ", +" ........ "}; diff --git a/examples/clickme.jpg b/examples/clickme.jpg new file mode 100644 index 0000000..50419c3 Binary files /dev/null and b/examples/clickme.jpg differ diff --git a/examples/fmlogo.gif b/examples/fmlogo.gif new file mode 100644 index 0000000..9fe5503 Binary files /dev/null and b/examples/fmlogo.gif differ diff --git a/examples/fmsynth.gpd b/examples/fmsynth.gpd new file mode 100644 index 0000000..e6b25b4 --- /dev/null +++ b/examples/fmsynth.gpd @@ -0,0 +1,442 @@ +328 +467 +#c0c0c0 +localhost +32781|1|2|5|10|0|1|FM Synth|0|0|0|0|1|5|0 +4 + +16 +57 +294 +259 +srectangle0 +rrectangle0 +#c0c0c0 +#000080 +22 +74 +93 +90 +0 +Arial +!END-CONTROL +5 +Carrier Freq +38 +105 +67 +20 +stext0 +rtext0 +#c0c0c0 +#000000 +12 +74 +90 +90 +0 +Arial +!END-CONTROL +2 +100 +34 +124 +24 +139 +carrier +rslider0 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Sans Serif +100 +5000 +1 +!END-CONTROL +5 +Mod Freq +141 +105 +59 +20 +stext0 +rtext0 +#c0c0c0 +#000000 +12 +74 +90 +90 +0 +Arial +!END-CONTROL +2 +0 +140 +124 +24 +139 +mod +rslider0 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Sans Serif +0 +500 +1 +!END-CONTROL +5 +Index +235 +105 +52 +20 +stext0 +rtext0 +#c0c0c0 +#000000 +12 +74 +90 +90 +0 +Arial +!END-CONTROL +2 +0 +243 +124 +24 +139 +index +rslider0 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Sans Serif +0 +1000 +1 +!END-CONTROL +5 +Amplitude: +34 +340 +73 +20 +stext2 +rtext2 +#c0c0c0 +#000000 +12 +74 +90 +90 +0 +Arial +!END-CONTROL +3 +0 +35 +364 +140 +24 +amp +rslider1 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Sans Serif +0 +100 +1 +!END-CONTROL +14 +./fmlogo.gif +77 +5 +180 +48 +simage3 +rimage3 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./scale.gif +58 +124 +23 +139 +simage7 +rimage7 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./scale.gif +164 +124 +23 +139 +simage7 +rimage7 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./scale.gif +268 +124 +23 +139 +simage7 +rimage7 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./scale2.gif +36 +389 +139 +23 +simage48 +rimage48 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +4 + +16 +309 +294 +124 +srectangle10 +rrectangle10 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +9 +100 +36 +267 +34 +20 +stextbox0 +carrier +#d6dcf8 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +9 +0 +142 +267 +34 +20 +stextbox0 +mod +#d6dcf8 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +9 +0 +245 +267 +34 +20 +stextbox0 +index +#d6dcf8 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +9 +0 +113 +337 +34 +20 +stextbox0 +amp +#d6dcf8 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./screw.gif +3 +2 +19 +19 +simage5 +rimage5 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./screw.gif +305 +2 +19 +19 +simage5 +rimage5 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./screw.gif +305 +438 +19 +19 +simage5 +rimage5 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +14 +./screw.gif +3 +438 +19 +19 +simage5 +rimage5 +#c0c0c0 +#000000 +8 +74 +90 +90 +0 +MS Shell Dlg +!END-CONTROL +1 +Mute +216 +381 +81 +35 +mute +rtoggle0 +#c0c0c0 +#000000 +14 +74 +90 +90 +0 +Arial +!END-CONTROL +1 +On/Off +216 +333 +81 +35 +onoff +rtoggle0 +#c0c0c0 +#000000 +14 +74 +90 +90 +0 +Arial +!END-CONTROL diff --git a/examples/gripd.gpd b/examples/gripd.gpd new file mode 100644 index 0000000..4aa7645 --- /dev/null +++ b/examples/gripd.gpd @@ -0,0 +1,380 @@ +493 +433 +#c3c3c3 +localhost +3490|/dev/js0|/dev/js1|5|10|1|1|GrIPD|0|0|0|0|1|5|1 +4 +rectangle0 +15 +5 +462 +358 +srectangle0 +rrectangle0 +#828282 +#303030 +12 +74 +90 +90 +0 + +!END-CONTROL +0 +button0 +37 +37 +80 +22 +sbutton0 +rbutton0 +#828282 +#303030 +12 +74 +90 +90 +0 + +!END-CONTROL +1 +toggle0 +59 +75 +80 +22 +stoggle0 +rtoggle0 +#828282 +#303030 +12 +74 +90 +90 +0 + +!END-CONTROL +2 +100 +271 +31 +30 +80 +sslider0 +rslider0 +#828282 +#303030 +12 +74 +90 +90 +0 + +0 +100 +1 +!END-CONTROL +3 +0 +276 +110 +80 +30 +sslider1 +rslider1 +#828282 +#303030 +12 +74 +90 +90 +0 + +0 +100 +1 +!END-CONTROL +6 +0 +33 +225 +30 +80 +sgauge0 +rgauge0 +#a2a2a2 +#303030 +12 +74 +90 +90 +0 + +0 +100 +0 +!END-CONTROL +7 +0 +34 +313 +80 +30 +sgauge1 +rgauge1 +#a2a2a2 +#303030 +12 +74 +90 +90 +0 + +0 +100 +0 +!END-CONTROL +8 +checkbox0 +109 +232 +85 +24 +scheckbox0 +rcheckbox0 +#828282 +#303030 +12 +74 +90 +90 +0 + +!END-CONTROL +5 +text0 +167 +34 +79 +14 +stext0 +rtext0 +#828282 +#303030 +12 +74 +90 +90 +0 + +!END-CONTROL +10 +0 +96 +113 +15 +26 +sspinbutton0 +rspinbutton0 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +0 +100 +0 +!END-CONTROL +9 + +41 +183 +80 +22 +stextbox0 +rtextbox0 +#ffffff +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +5 +<- "Enter" to send +118 +185 +120 +15 +stext1 +rtext1 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +11 + +265 +155 +100 +100 +smousearea0 +rmousearea0 +#9a9a9a +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +5 +<- Left click and +363 +170 +96 +19 +stext2 +rtext2 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +5 +drag to track +380 +185 +80 +16 +stext4 +rtext4 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +5 +mouse position +384 +200 +83 +22 +stext5 +rtext5 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +13 +radiobutton0 +164 +87 +93 +24 +sradiobutton0 +rradiobutton0 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +12 +radiobutton1 +164 +112 +93 +24 +sradiobutton1 +rradiobutton1 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +12 +radiobutton2 +164 +137 +93 +24 +sradiobutton2 +rradiobutton2 +#c3c3c3 +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +14 +./clickme.jpg +178 +276 +192 +71 +simage0 +rimage0 +#dddddd +#000000 +12 +74 +90 +90 +0 + +!END-CONTROL +15 + +366 +26 +100 +100 +sgraph0 +rgraph0 +#000000 +#00ff00 +12 +74 +90 +90 +0 + +-1.0 +1.0 +[100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +!END-CONTROL diff --git a/examples/gripd.pd b/examples/gripd.pd new file mode 100644 index 0000000..42c75ed --- /dev/null +++ b/examples/gripd.pd @@ -0,0 +1,73 @@ +#N canvas 420 51 695 867 10; +#X obj 22 747 gripd; +#X msg 23 40 connect; +#X msg 38 75 disconnect; +#X msg 117 445 poll_send 5; +#X msg 124 470 poll_receive 5; +#X msg 126 501 set_path ../gripd; +#X msg 89 631 set_python_path c:/program files/python; +#X text 369 661 "c:/program files/python" by default.; +#X text 372 678 Linux: Does nothing.; +#X text 229 471 Time in ms to poll for info from GUI.; +#X text 199 446 Time in ms to poll for sending info to GUI.; +#X text 62 747 Takes one optional argument to specify a port.; +#X text 82 15 all backslashes must be "/".; +#X text 19 2 Windows: For paths \, spaces are ok \, but; +#X text 120 67 Set gripd object to stop waiting for a connection.; +#X text 121 80 Also closes gripd GUI opened by "open ".; +#X text 86 34 Set gripd object to wait for a connection (Not needed +with "open" message.); +#X floatatom 22 802 5 0 0 0 - - -; +#X msg 105 376 lock; +#X msg 115 407 unlock; +#X msg 49 112 open ../gripd/examples/gripd.gpd; +#X msg 52 219 open_locked ../gripd/examples/gripd.gpd; +#X text 144 376 Set GUI to lock mode; +#X text 164 407 Set GUI to normal (editable) mode; +#X text 283 168 Relative paths are relative to the directory; +#X text 283 180 containing PD executable.; +#X text 255 568 Relative paths are relative to the directory; +#X text 254 583 containing PD executable.; +#X text 68 803 left outlet: 1 on connect \, 0 on disconnect; +#X floatatom 52 780 5 0 0 0 - - -; +#X text 96 781 right outlet: 1 when shown \, 0 when hidden; +#X msg 59 248 show; +#X msg 68 276 hide; +#X text 96 249 show GUI window when hidden; +#X text 106 275 hide GUI window when shown; +#X text 372 645 Normally not needed (used for gripd.py); +#X text 371 629 Windows: Path to directory containing python.exe.; +#X text 283 108 Open gripd GUI and optional .gpd file \, and connect. +; +#X text 330 219 Open gripd GUI in locked mode; +#X text 348 135 If it fails tries gripd.py via python.exe.; +#X text 284 121 Windows: first tries to execute gripd.exe.; +#X text 255 503 Path to directory containing gripd executable; +#X text 255 519 "../gripd" by default; +#X text 254 535 Windows: sets path to file gripd.exe (and gripd.py). +; +#X text 255 552 Linux: sets path to file gripd (symlink to gripd.py). +; +#X text 284 155 Linux: executes file gripd; +#X msg 79 309 openpanel; +#X msg 89 340 savepanel; +#X text 156 340 open a save file dialog and send file to savepanel +receive symbol; +#X text 152 303 open an open file dialog and send file to openpanel +receive symbol; +#X connect 0 0 17 0; +#X connect 0 1 29 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 3 0 0 0; +#X connect 4 0 0 0; +#X connect 5 0 0 0; +#X connect 6 0 0 0; +#X connect 18 0 0 0; +#X connect 19 0 0 0; +#X connect 20 0 0 0; +#X connect 21 0 0 0; +#X connect 31 0 0 0; +#X connect 32 0 0 0; +#X connect 46 0 0 0; +#X connect 47 0 0 0; diff --git a/examples/gripdExamples.pd b/examples/gripdExamples.pd new file mode 100644 index 0000000..950cfa3 --- /dev/null +++ b/examples/gripdExamples.pd @@ -0,0 +1,247 @@ +#N canvas 249 58 823 654 10; +#X obj 19 198 r sbutton0; +#X obj 19 177 s rbutton0; +#X obj 138 176 s rtoggle0; +#X obj 138 197 r stoggle0; +#X msg 205 151 bang; +#X msg 243 151 New label; +#X msg 19 154 New label; +#X msg 170 151 1; +#X msg 138 151 0; +#X obj 23 278 s rslider0; +#X obj 23 299 r sslider0; +#X floatatom 23 257 4 0 0 0 - - -; +#X floatatom 23 320 4 0 0 0 - - -; +#X floatatom 110 257 4 0 0 0 - - -; +#X floatatom 110 320 4 0 0 0 - - -; +#X obj 110 278 s rslider1; +#X obj 110 299 r sslider1; +#X floatatom 215 257 4 0 0 0 - - -; +#X floatatom 215 299 4 0 0 0 - - -; +#X obj 215 278 s rgauge0; +#X obj 215 320 s rgauge1; +#X obj 293 283 s rtext0; +#X msg 334 262 New label; +#X floatatom 25 361 4 0 0 0 - - -; +#X floatatom 25 424 4 0 0 0 - - -; +#X obj 25 382 s rspinbutton0; +#X obj 25 403 r sspinbutton0; +#X floatatom 152 360 4 0 0 0 - - -; +#X obj 152 381 s rtextbox0; +#X msg 194 360 New text; +#X obj 152 403 r stextbox0; +#X floatatom 286 262 4 0 0 0 - - -; +#X obj 378 356 r smousearea0; +#X obj 324 406 change; +#X obj 375 405 change; +#X floatatom 324 427 4 0 0 0 - - -; +#X floatatom 375 426 4 0 0 0 - - -; +#X floatatom 697 45 7 0 0 0 - - -; +#X floatatom 698 83 5 0 0 0 - - -; +#X obj 17 480 r sradiobutton0; +#X obj 137 501 s rradiobutton0; +#X msg 137 480 bang; +#X msg 137 522 bang; +#X msg 137 564 bang; +#X obj 137 597 s rradiobutton2; +#X obj 137 543 s rradiobutton1; +#X obj 17 522 r sradiobutton1; +#X obj 17 566 r sradiobutton2; +#X obj 698 62 r joy0button0; +#X floatatom 21 131 5 0 0 0 - - -; +#X obj 697 24 r joy0axis0; +#X obj 588 23 r keystroke; +#X obj 616 519 s rimage0; +#X msg 628 495 ./clickme.jpg; +#X text 615 558 relative to directory; +#X text 615 576 containing .gpd file; +#X msg 616 472 ./poof.jpg; +#X text 615 594 Must use ./ or ../ to; +#X text 615 612 specify a relative path; +#X text 252 6 <- click here to open GUI; +#X text 615 539 Relative image paths are; +#X text 256 45 relative to directory; +#X text 256 81 Must use ./ or ../ to; +#X text 256 99 specify a relative path; +#X text 256 26 Relative paths are; +#X text 255 62 containing PD executable; +#X obj 378 377 unpack f f f f; +#X floatatom 426 405 4 0 0 0 - - -; +#X floatatom 503 405 4 0 0 0 - - -; +#X text 324 442 x \, y position; +#X text 426 421 0 - left; +#X text 426 432 1 - middle; +#X text 426 443 2 - right; +#X text 504 421 1 - down; +#X text 504 432 0 - up; +#X floatatom 76 110 5 0 0 0 - - -; +#X obj 588 45 unpack; +#X floatatom 588 72 7 0 0 0 - - -; +#X floatatom 644 72 5 0 0 0 - - -; +#X msg 39 29 show; +#X msg 76 29 hide; +#X obj 532 225 r midi0note; +#X obj 532 250 unpack f f f; +#X floatatom 532 275 5 0 0 0 - - -; +#X floatatom 575 275 5 0 0 0 - - -; +#X floatatom 618 275 5 0 0 0 - - -; +#X floatatom 659 274 5 0 0 0 - - -; +#X floatatom 702 274 5 0 0 0 - - -; +#X obj 659 224 r midi0ctl; +#X floatatom 533 200 5 0 0 0 - - -; +#X floatatom 576 200 5 0 0 0 - - -; +#X obj 533 175 unpack; +#X obj 533 150 r midi0pgm; +#X text 63 131 <- connection status; +#X text 116 108 <- shown or hidden; +#X msg 262 360 bang; +#X text 298 361 <- clear; +#X obj 326 536 change; +#X obj 377 535 change; +#X floatatom 326 557 4 0 0 0 - - -; +#X floatatom 377 556 4 0 0 0 - - -; +#X obj 380 507 unpack f f f f; +#X floatatom 428 535 4 0 0 0 - - -; +#X floatatom 505 535 4 0 0 0 - - -; +#X text 326 572 x \, y position; +#X text 428 551 0 - left; +#X text 428 562 1 - middle; +#X text 428 573 2 - right; +#X text 506 551 1 - down; +#X text 506 562 0 - up; +#X obj 380 483 r simage0; +#X msg 21 6 open ../gripd/examples/gripd.gpd; +#X obj 659 249 unpack f f f; +#X floatatom 742 274 5 0 0 0 - - -; +#X msg 549 498 show; +#X msg 576 472 hide; +#X msg 386 151 bang; +#X msg 436 151 New label; +#X msg 349 151 1; +#X msg 319 151 0; +#X obj 319 178 s rcheckbox0; +#X obj 319 200 r scheckbox0; +#X msg 17 501 0; +#X msg 17 543 1; +#X msg 17 587 2; +#X floatatom 17 617 5 0 0 0 - - -; +#X obj 19 219 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 +-1; +#X obj 138 221 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 +1; +#X obj 319 224 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 +1; +#X obj 631 416 s rgraph0; +#X floatatom 631 343 5 0 0 0 - - -; +#X obj 631 383 pack; +#X floatatom 674 343 5 0 0 0 - - -; +#X floatatom 682 390 5 0 0 0 - - -; +#X obj 21 86 gripd 3490; +#X text 724 390 <- set size; +#X obj 631 361 i; +#X obj 674 364 t b f; +#X obj 547 344 r sgraph0; +#X obj 547 367 unpack; +#X floatatom 547 392 5 0 0 0 - - -; +#X floatatom 587 392 5 0 0 0 - - -; +#X msg 124 33 openpanel; +#X msg 124 57 savepanel; +#X text 629 325 set data: index \, value; +#X obj 152 425 print textbox; +#X obj 456 71 r openpanel; +#X obj 456 98 print openpanel; +#X obj 458 21 r savepanel; +#X obj 458 48 print savepanel; +#X msg 453 263 New label; +#X floatatom 405 263 4 0 0 0 - - -; +#X obj 412 284 s rrectangle0; +#X connect 0 0 126 0; +#X connect 3 0 127 0; +#X connect 4 0 2 0; +#X connect 5 0 2 0; +#X connect 6 0 1 0; +#X connect 7 0 2 0; +#X connect 8 0 2 0; +#X connect 10 0 12 0; +#X connect 11 0 9 0; +#X connect 13 0 15 0; +#X connect 16 0 14 0; +#X connect 17 0 19 0; +#X connect 18 0 20 0; +#X connect 22 0 21 0; +#X connect 23 0 25 0; +#X connect 26 0 24 0; +#X connect 27 0 28 0; +#X connect 29 0 28 0; +#X connect 30 0 145 0; +#X connect 31 0 21 0; +#X connect 32 0 66 0; +#X connect 33 0 35 0; +#X connect 34 0 36 0; +#X connect 39 0 122 0; +#X connect 41 0 40 0; +#X connect 42 0 45 0; +#X connect 43 0 44 0; +#X connect 46 0 123 0; +#X connect 47 0 124 0; +#X connect 48 0 38 0; +#X connect 50 0 37 0; +#X connect 51 0 76 0; +#X connect 53 0 52 0; +#X connect 56 0 52 0; +#X connect 66 0 33 0; +#X connect 66 1 34 0; +#X connect 66 2 67 0; +#X connect 66 3 68 0; +#X connect 76 0 77 0; +#X connect 76 1 78 0; +#X connect 79 0 134 0; +#X connect 80 0 134 0; +#X connect 81 0 82 0; +#X connect 82 0 83 0; +#X connect 82 1 84 0; +#X connect 82 2 85 0; +#X connect 88 0 112 0; +#X connect 91 0 89 0; +#X connect 91 1 90 0; +#X connect 92 0 91 0; +#X connect 95 0 28 0; +#X connect 97 0 99 0; +#X connect 98 0 100 0; +#X connect 101 0 97 0; +#X connect 101 1 98 0; +#X connect 101 2 102 0; +#X connect 101 3 103 0; +#X connect 110 0 101 0; +#X connect 111 0 134 0; +#X connect 112 0 86 0; +#X connect 112 1 87 0; +#X connect 112 2 113 0; +#X connect 114 0 52 0; +#X connect 115 0 52 0; +#X connect 116 0 120 0; +#X connect 117 0 120 0; +#X connect 118 0 120 0; +#X connect 119 0 120 0; +#X connect 121 0 128 0; +#X connect 122 0 125 0; +#X connect 123 0 125 0; +#X connect 124 0 125 0; +#X connect 130 0 136 0; +#X connect 131 0 129 0; +#X connect 132 0 137 0; +#X connect 133 0 129 0; +#X connect 134 0 49 0; +#X connect 134 1 75 0; +#X connect 136 0 131 0; +#X connect 137 0 136 0; +#X connect 137 1 131 1; +#X connect 138 0 139 0; +#X connect 139 0 140 0; +#X connect 139 1 141 0; +#X connect 142 0 134 0; +#X connect 143 0 134 0; +#X connect 146 0 147 0; +#X connect 148 0 149 0; +#X connect 150 0 152 0; +#X connect 151 0 152 0; diff --git a/examples/gripdFM.pd b/examples/gripdFM.pd new file mode 100644 index 0000000..28cccf6 --- /dev/null +++ b/examples/gripdFM.pd @@ -0,0 +1,135 @@ +#N canvas 660 45 549 445 10; +#X obj 202 183 *~; +#X floatatom 202 126 0 0 0 0 - - -; +#X obj 267 161 line~; +#X floatatom 114 146 0 0 0 0 - - -; +#X obj 114 268 cos~; +#X obj 114 216 +~; +#X floatatom 143 316 0 0 0 0 - - -; +#N canvas 159 26 495 270 output 0; +#X obj 338 160 t b; +#X obj 338 110 f; +#X obj 338 60 inlet; +#X text 344 29 mute; +#X obj 338 185 f; +#X msg 425 178 0; +#X msg 338 85 bang; +#X obj 338 135 moses 1; +#X obj 425 153 t b f; +#X obj 397 117 moses 1; +#X obj 83 148 dbtorms; +#X obj 397 92 r master-lvl; +#X obj 83 42 r master-lvl; +#X obj 338 210 s master-lvl; +#X obj 22 182 inlet~; +#X obj 199 41 inlet; +#X text 199 18 level; +#X obj 199 100 s master-lvl; +#X msg 96 65 set \$1; +#X obj 96 89 outlet; +#X msg 214 64 \; pd dsp 1; +#X obj 83 194 line~; +#X obj 22 212 *~; +#X obj 22 241 dac~; +#X obj 83 171 pack 0 50; +#X text 20 159 audio; +#X text 93 110 show level; +#X connect 0 0 4 0; +#X connect 1 0 7 0; +#X connect 2 0 6 0; +#X connect 4 0 13 0; +#X connect 5 0 13 0; +#X connect 6 0 1 0; +#X connect 7 0 0 0; +#X connect 7 1 8 0; +#X connect 8 0 5 0; +#X connect 9 1 4 1; +#X connect 10 0 24 0; +#X connect 11 0 1 1; +#X connect 11 0 9 0; +#X connect 12 0 10 0; +#X connect 12 0 18 0; +#X connect 14 0 22 0; +#X connect 15 0 17 0; +#X connect 15 0 20 0; +#X connect 18 0 19 0; +#X connect 21 0 22 1; +#X connect 22 0 23 0; +#X connect 22 0 23 1; +#X connect 24 0 21 0; +#X restore 114 344 pd output; +#X msg 172 316 MUTE; +#X text 213 316 <-- output amplitude; +#X msg 229 262 bang; +#X text 266 263 <-- click to graph; +#X obj 114 173 phasor~ 0; +#X obj 202 151 osc~ 0; +#X text 33 8 PHASE MODULATION ("FM") USING TWO OSCILLATORS; +#X obj 229 286 tabwrite~ fm-output; +#X obj 267 135 pack 0 50; +#X floatatom 267 82 0 0 0 0 - - -; +#X obj 267 109 / 100; +#X text 263 50 modulation index; +#X text 263 65 in hundredths; +#X text 111 103 carrier; +#X text 110 121 frequency; +#X text 187 102 frequency; +#X text 188 85 modulation; +#X text 310 160 <-- signal with smoothed; +#X text 312 176 modulation index to avoid clicks; +#X text 188 345 <-- as in previous patch; +#X text 199 205 amplitude-controlled modulation; +#X text 200 222 oscillator output; +#X text 37 158 carrier; +#X text 37 173 phase -->; +#X text 18 201 phase; +#X text 17 216 modulation-->; +#X text 14 252 output; +#X text 15 268 waveform -->; +#X obj 51 81 r carrier; +#X obj 148 65 r mod; +#X obj 207 30 r index; +#X obj 129 291 r amp; +#X obj 172 245 r mute; +#X msg 438 85 \; pd dsp \$1; +#X obj 438 52 r onoff; +#X obj 27 402 gripd; +#X text 329 377 <-- Click; +#X text 341 402 open GUI; +#X text 347 389 here to; +#N canvas 132 85 450 293 array 0; +#N canvas 0 0 450 300 graph1 0; +#X array fm-output 100 float 0; +#X coords 0 1 99 -1 200 140 1; +#X restore 100 20 graph; +#X restore 417 256 pd array; +#X msg 27 374 open_locked ../gripd/examples/fmsynth.gpd; +#X msg 67 402 show; +#X msg 100 402 unlock; +#X msg 150 402 lock; +#X connect 0 0 5 1; +#X connect 1 0 13 0; +#X connect 2 0 0 1; +#X connect 3 0 12 0; +#X connect 4 0 15 0; +#X connect 4 0 7 0; +#X connect 5 0 4 0; +#X connect 6 0 7 1; +#X connect 7 0 6 0; +#X connect 8 0 7 2; +#X connect 10 0 15 0; +#X connect 12 0 5 0; +#X connect 13 0 0 0; +#X connect 16 0 2 0; +#X connect 17 0 18 0; +#X connect 18 0 16 0; +#X connect 36 0 3 0; +#X connect 37 0 1 0; +#X connect 38 0 17 0; +#X connect 39 0 6 0; +#X connect 40 0 8 0; +#X connect 42 0 41 0; +#X connect 48 0 43 0; +#X connect 49 0 43 0; +#X connect 50 0 43 0; +#X connect 51 0 43 0; diff --git a/examples/poof.jpg b/examples/poof.jpg new file mode 100644 index 0000000..d15a262 Binary files /dev/null and b/examples/poof.jpg differ diff --git a/examples/scale.gif b/examples/scale.gif new file mode 100644 index 0000000..61c6def Binary files /dev/null and b/examples/scale.gif differ diff --git a/examples/scale2.gif b/examples/scale2.gif new file mode 100644 index 0000000..95d1e95 Binary files /dev/null and b/examples/scale2.gif differ diff --git a/examples/screw.gif b/examples/screw.gif new file mode 100644 index 0000000..1ebd9ae Binary files /dev/null and b/examples/screw.gif differ diff --git a/gripd b/gripd new file mode 100755 index 0000000..3e9fb38 --- /dev/null +++ b/gripd @@ -0,0 +1,42 @@ +#!/usr/bin/python -OO + +## GrIPD v0.1.1 - Graphical Interface for Pure Data +## Copyright (C) 2003 Joseph A. Sarlo +## +## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## jsarlo@ucsd.edu + +from wxPython.wx import * +from gripdMain import * +import sys +import signal +import os + +def signalHandler(sigNum, frame): + print 'Caught signal', sigNum + try: + app.frame.eClose(wxEvent()) + except: + app.ExitMainLoop() +if (os.name == "posix"): + signal.signal(signal.SIGQUIT, signalHandler) + signal.signal(signal.SIGINT, signalHandler) + signal.signal(signal.SIGTERM, signalHandler) +app = mainApp(sys.argv) +app.MainLoop() + + + diff --git a/gripd.opt b/gripd.opt new file mode 100644 index 0000000..411fd79 --- /dev/null +++ b/gripd.opt @@ -0,0 +1,2 @@ +joystick = TRUE +midi = TRUE diff --git a/gripd.py b/gripd.py new file mode 100644 index 0000000..beb6047 --- /dev/null +++ b/gripd.py @@ -0,0 +1,43 @@ +#!/usr/bin/python -OO + +## GrIPD v0.1.1 - Graphical Interface for Pure Data +## Copyright (C) 2003 Joseph A. Sarlo +## +## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## jsarlo@ucsd.edu + +from wxPython.wx import * +from gripdMain import * +import sys +import signal +import os + +def signalHandler(sigNum, frame): + print 'Caught signal', sigNum + try: + app.frame.eClose(wxEvent()) + except: + app.ExitMainLoop() +if (os.name == "posix"): + signal.signal(signal.SIGQUIT, signalHandler) + signal.signal(signal.SIGINT, signalHandler) + signal.signal(signal.SIGTERM, signalHandler) +app = mainApp(sys.argv) +app.MainLoop() + + + + diff --git a/gripd.spec b/gripd.spec new file mode 100644 index 0000000..453270c --- /dev/null +++ b/gripd.spec @@ -0,0 +1,16 @@ +a = Analysis(['../../support/_mountzlib.py', + '../../support/useUnicode.py', + 'src/gripd.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts + [('OO','','OPTION')] + [('f','','OPTION')], + exclude_binaries=1, + name='buildgripd/gripd', + debug=0, + strip=1, + console=1 ) +coll = COLLECT( exe, + a.binaries, + strip=1, + name='distgripd') diff --git a/gripdControls.py b/gripdControls.py new file mode 100644 index 0000000..10ebc1e --- /dev/null +++ b/gripdControls.py @@ -0,0 +1,1675 @@ +## GrIPD v0.1.1 - Graphical Interface for Pure Data +## Copyright (C) 2003 Joseph A. Sarlo +## +## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## jsarlo@ucsd.edu + +from wxPython.wx import * +from string import * +from gripdFunctions import * +import os +import math + +MBUTTONTYPE = 0 +MTOGGLETYPE = 1 +MVSLIDERTYPE = 2 +MHSLIDERTYPE = 3 +MRECTTYPE = 4 +MTEXTTYPE = 5 +MVGAUGETYPE = 6 +MHGAUGETYPE = 7 +MCHECKBOXTYPE = 8 +MTEXTBOXTYPE = 9 +MSPINBUTTONTYPE = 10 +MMOUSEAREATYPE = 11 +MRADIOBUTTONTYPE = 12 +MRADIONEWTYPE = 13 +MIMAGETYPE = 14 +MGRAPHTYPE = 15 +PAIRSEPCHAR = chr(29) +SYMMSGSEP = chr(31) +DEFCONTROLID = -1 +DEFEDITPOS = (5,7) +DEFSLIDERVALUE = 0 +DEFSLIDERMIN = 0 +DEFSLIDERMAX = 100 +DEFVSLIDERSIZE = (30, 80) +DEFHSLIDERSIZE = (80, 30) +DEFRECTSIZE = (200, 200) +DEFVGAUGESIZE = (30, 80) +DEFHGAUGESIZE = (80, 30) +DEFGAUGEMIN = 0 +DEFGAUGEMAX = 100 +DEFTAGSIZE = 9 +RESIZETAGCOLOR = "#555555" +DEFMOUSEAREASIZE = 100 +SETRCVRCOMMAND = "!setRcvr" +SETARRAYCOMMAND = "!setArray" +TEXTEDITINPUT = 0 +FONTEDITINPUT = 1 +COLOREDITINPUT = 2 +FILEEDITINPUT = 3 +DROPDOWNEDITINPUT = 4 +MAXARRAYSENDSIZE = 2000 + +lastEditWindowPosition = (-1, -1) + +# Abstract class for controls (buttons, sliders, etc) +class mControl(wxControl): + def __init__(self, parentApp, type, sSym, rSym, cnxtn): + self.editMode = False + self.selected = False + self.parentApp = parentApp + self.type = type + self.sendSymbol = sSym + self.receiveSymbol = rSym + self.connection = cnxtn + self.resetBackground = False + self.updateRSym() + self.clickedOn = False + self.grabbed = False + self.setEditMode(True) + EVT_CHAR(self, self.eChar) + EVT_KEY_UP(self, self.parentApp.eKeyUp) + EVT_KEY_DOWN(self, self.parentApp.eKeyDown) + def mDestroy(self): + if (self.editMode): + self.moveTag.Destroy() + self.BLResizeTag.Destroy() + self.BRResizeTag.Destroy() + self.TRResizeTag.Destroy() + self.Destroy() + def select(self): + if (not self.selected): + self.relocateTags() + self.moveTag.Show(True) + self.BLResizeTag.Show(True) + self.BRResizeTag.Show(True) + self.TRResizeTag.Show(True) + self.parentApp.selectedControlList.append(self) + # To keep tags above controls in Windows, repaints tags in idle time + # (i.e. after everything else has bee repainted) + self.selected = True + self.Connect(-1, -1, EVT_RAISE_TAGS_ID, self.eRepaintControlTags) + wxPostEvent(self, RaiseTagsEvent()) + def deselect(self): + if (self.selected): + self.moveTag.Show(False) + self.BLResizeTag.Show(False) + self.BRResizeTag.Show(False) + self.TRResizeTag.Show(False) + self.parentApp.selectedControlList.remove(self) + self.Disconnect(-1, EVT_RAISE_TAGS_ID) + self.selected = False + def isSelected(self): + return self.selected + def grab(self): + if (not self.grabbed): + self.grabbed = True + self.parentApp.dragging = True + EVT_MOTION(self.moveTag, self.moveTag.eMove) + self.moveTag.lastPos = wxGetMousePosition() + self.moveTag.SetCursor(wxStockCursor(self.moveTag.pointerStyle)) + self.parentApp.startMoveControls() + self.moveTag.CaptureMouse() + def ungrab(self): + if (self.grabbed): + self.grabbed = False + self.parentApp.dragging = False + self.moveTag.ReleaseMouse() + # this doesn't seem to actually disconnect + self.moveTag.Disconnect(-1, wxEVT_MOTION) + self.moveTag.SetCursor(wxSTANDARD_CURSOR) + self.parentApp.endDragMoveControls() + self.parentApp.mainFrame.mainPanel.Refresh() + self.Refresh() + def updateRSym(self): + self.connection.send(SETRCVRCOMMAND + SYMMSGSEP + \ + self.receiveSymbol + PAIRSEPCHAR) + def sendMessage(self, message): + try: + self.connection.send(self.sendSymbol + SYMMSGSEP + \ + message + PAIRSEPCHAR) + except: + pass + def PDAction(self, value): + self.SetLabel(value) + def relocateTags(self): + self.moveTag.relocate() + self.BLResizeTag.relocate() + self.BRResizeTag.relocate() + self.TRResizeTag.relocate() + def refreshTags(self): + self.moveTag.Show(True) + self.BLResizeTag.Show(True) + self.BRResizeTag.Show(True) + self.TRResizeTag.Show(True) + self.moveTag.Refresh() + self.BLResizeTag.Refresh() + self.BRResizeTag.Refresh() + self.TRResizeTag.Refresh() + def startMove(self): + self.TRResizeTag.Show(False) + self.BRResizeTag.Show(False) + self.BLResizeTag.Show(False) + def move(self, deltaPos): + if (self.editMode and self.isSelected()): + xPos = self.GetPosition()[0] + deltaPos[0] + yPos = self.GetPosition()[1] + deltaPos[1] + deltaPosMTX = xPos - self.GetPosition()[0] + deltaPosMTY = yPos - self.GetPosition()[1] + xMTPos = self.moveTag.GetPosition()[0] + deltaPosMTX + yMTPos = self.moveTag.GetPosition()[1] + deltaPosMTY + self.MoveXY(xPos, yPos) + self.moveTag.MoveXY(xMTPos, yMTPos) + def endMove(self): + self.relocateTags() + self.TRResizeTag.Show(True) + self.BRResizeTag.Show(True) + self.BLResizeTag.Show(True) + def endDragMove(self): + if (self.parentApp.snapToGrid): + self.setPosition( \ + self.parentApp.getNearestGridPoint(self.GetPosition())) + self.endMove() + def resize(self, deltaPos): + if (self.editMode): + xSize = self.GetSize()[0] + deltaPos[0] + ySize = self.GetSize()[1] + deltaPos[1] + if (xSize > 0 and ySize > 0): + self.setSize((xSize, ySize)) + def setEditMode(self, mode): + if (mode): + if (not self.editMode): + EVT_LEFT_DOWN(self, self.eLeftDown) + EVT_RIGHT_DOWN(self, self.eRightDown) + self.moveTag = controlEditTag(self, + (0,0), + wxBLACK, + wxCURSOR_CROSS) + self.BLResizeTag = controlResizeTag(self, + (1,0), + RESIZETAGCOLOR, + wxCURSOR_SIZEWE) + self.TRResizeTag = controlResizeTag(self, + (0,1), + RESIZETAGCOLOR, + wxCURSOR_SIZENS) + self.BRResizeTag = controlResizeTag(self, + (1,1), + RESIZETAGCOLOR, + wxCURSOR_SIZENWSE) + self.editMode = True + elif (self.editMode): + self.deselect() + self.moveTag.Destroy() + self.BLResizeTag.Destroy() + self.TRResizeTag.Destroy() + self.BRResizeTag.Destroy() + self.Disconnect(-1, wxEVT_LEFT_DOWN) + self.Disconnect(-1, wxEVT_RIGHT_DOWN) + self.editMode = False + def getEditMode(self): + return self.editMode + def setSendSymbol(self, sym): + self.sendSymbol = sym + def getSendSymbol(self): + return self.sendSymbol + def setReceiveSymbol(self, sym): + self.receiveSymbol = sym + self.updateRSym() + def getReceiveSymbol(self): + return self.receiveSymbol + def setConnection(self, cnxtn): + self.connection = cnxtn + def getConnection(self): + return self.connection + def getType(self): + return self.type + def setPosition(self, pos): + self.MoveXY(pos[0], pos[1]) + self.relocateTags() + def setSize(self, size): + self.SetSize(size) + if (self.selected): + self.relocateTags() + # catch GTK bug + def GetBackgroundColour(self): + color = wxControl.GetBackgroundColour(self) + if (not color.Ok()): + color = wxBLACK + return color + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Position", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + self.SetLabel(editValues[6]) + self.SetForegroundColour(editValues[7]) + self.SetBackgroundColour(editValues[8]) + self.SetFont(editValues[9]) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("Width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("Label:", + TEXTEDITINPUT, + self.GetLabel()) + editor.addEditItem("F Color:", + COLOREDITINPUT, + self.GetForegroundColour()) + editor.addEditItem("B Color:", + COLOREDITINPUT, + self.GetBackgroundColour()) + editor.addEditItem("Font:", + FONTEDITINPUT, + self.GetFont()) + editor.edit() + def eChar(self, event): + self.parentApp.eChar(event) + def eLeftDown(self, event): + if (self.editMode): + if (event.ControlDown()): + if (self.isSelected()): + self.deselect() + else: + self.select() + else: + self.parentApp.deselectOthers(self.GetId()) + self.select() + else: + event.Skip() + def eRightDown(self, event): + if (self.editMode): + self.parentApp.deselectOthers(self.GetId()) + self.select() + self.eEdit(event) + else: + event.Skip() + def eRepaintControlTags(self, event): + self.refreshTags() + +# Class for little box user grabs to move/edit control +class controlEditTag(wxPanel): + def __init__(self, parentControl, position, color, pointerStyle): + wxPanel.__init__(self, + parentControl.parentApp.mainFrame.mainPanel, + -1, (0,0), + (DEFTAGSIZE, DEFTAGSIZE), 0) + self.SetBackgroundColour(color) + self.parentControl = parentControl + self.pointerStyle = pointerStyle + self.leftDownOnTag = False + self.position = position + EVT_CHAR(self, self.parentControl.parentApp.eChar) + EVT_KEY_UP(self, self.parentControl.parentApp.eKeyUp) + EVT_KEY_DOWN(self, self.parentControl.parentApp.eKeyDown) + EVT_LEFT_DOWN(self, self.eLeftDown) + EVT_LEFT_UP(self, self.eRelease) + EVT_RIGHT_DOWN(self, self.eRightDown) + EVT_ENTER_WINDOW(self, self.eEnter) + EVT_LEAVE_WINDOW(self, self.eLeave) + self.Show(False) + def relocate(self): + nuPos = [0,0] + parentPos = self.parentControl.GetPosition() + parentSize = self.parentControl.GetSize() + if (self.position[0]): + nuPos[0] = parentPos[0] + parentSize[0] + else: + nuPos[0] = parentPos[0] - DEFTAGSIZE + if (self.position[1]): + nuPos[1] = parentPos[1] + parentSize[1] + else: + nuPos[1] = parentPos[1] - DEFTAGSIZE + self.MoveXY(nuPos[0], nuPos[1]) + def eLeftDown(self, event): + self.leftDownOnTag = True + if (self.parentControl.grabbed): + self.parentControl.ungrab() + self.parentControl.deselect() + self.parentControl.parentApp.deselectOthers(-1) + else: + self.parentControl.grab() + def eRightDown(self, event): + if (not self.parentControl.grabbed): + self.parentControl.eEdit(event) + def eMove(self, event): + if (self.parentControl.grabbed): + self.newPos = wxGetMousePosition() + deltaPos = (self.newPos[0] - self.lastPos[0], + self.newPos[1] - self.lastPos[1]) + self.lastPos = self.newPos + self.parentControl.parentApp.moveSelectedControls(deltaPos) + def eRelease(self, event): + self.leftDownOnTag = False + self.parentControl.ungrab() + def eEnter(self, event): + self.SetCursor(wxStockCursor(self.pointerStyle)) + def eLeave(self, event): + self.SetCursor(wxSTANDARD_CURSOR) +# Class for little box user grabs to resize control +class controlResizeTag(controlEditTag): + def eLeftDown(self, event): + EVT_MOTION(self, self.eMove) + self.leftDownOnTag = True + self.lastPos = wxGetMousePosition() + self.SetCursor(wxStockCursor(self.pointerStyle)) + self.CaptureMouse() + def eMove(self, event): + if (event.LeftIsDown() and self.leftDownOnTag): + self.newPos = wxGetMousePosition() + deltaPos = ((self.newPos[0] - self.lastPos[0]) * self.position[0], + (self.newPos[1] - self.lastPos[1]) * self.position[1]) + self.lastPos = self.newPos + self.parentControl.parentApp.resizeSelectedControls(deltaPos) + def eRelease(self, event): + self.ReleaseMouse() + self.Disconnect(-1, wxEVT_MOTION) + self.SetCursor(wxSTANDARD_CURSOR) + self.leftDownOnTag = False + self.parentControl.parentApp.mainFrame.mainPanel.Refresh() + +# Class for regular buttons +class mButton(mControl, wxButton): + def __init__(self, parentApp, type, id, text, pos, sSym, rSym, conn): + wxButton.__init__(self, parentApp.mainFrame.mainPanel, + id, text, pos) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + EVT_BUTTON(parentApp.mainFrame.mainPanel, + self.GetId(), self.eClicked) + def eClicked(self, event): + if (not self.editMode): + self.sendMessage("bang") + +# Class for toggle buttons +# Problem with grabbing clicks with EVT_*_DOWN mouse events +# in GTK on toggle button, seems to be a wxWindows thing +class mToggle(mButton, wxToggleButton, wxButton): + def __init__(self, parentApp, type, id, text, pos, sSym, rSym, conn): + wxToggleButton.__init__(self, parentApp.mainFrame.mainPanel, + id, text, pos) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + EVT_TOGGLEBUTTON(parentApp.mainFrame.mainPanel, + self.GetId(), self.eClicked) + def toggle(self): + self.SetValue(1 - self.GetValue()) + def PDAction(self, value): + try: + num = atof(value) + if (num == 0): + self.SetValue(0) + else: + self.SetValue(1) + except: + if (value == "bang"): + self.toggle() + else: + self.SetLabel(value) + def eClicked(self, event): + # checking edit mode due to above-mentioned problem + # checking for ctrl key (308) + if (self.editMode): + try: + self.parentApp.keysDown.index(308) + if (self.selected): + self.deselect() + else: + self.select() + except: + self.parentApp.deselectOthers(-1) + self.select() + else: + self.sendMessage(repr(event.IsChecked())) + +# Class for sliders +# Screwyness since wxSliders have a maximum at down position. +# No way to change as far as I can tell. +class mSlider(mControl, wxSlider): + def __init__(self, parentApp, type, id, label, + pos, style, sSym, rSym, conn): + if (style & wxSL_HORIZONTAL): + sSize = DEFHSLIDERSIZE + if (style & wxSL_VERTICAL): + sSize = DEFVSLIDERSIZE + if (isinstance(label, list)): + try: + value = atoi(label[0]) + except: + value = 0 + min = label[1] + max = label[2] + dir = label[3] + else: + try: + value = atoi(label) + except: + value = 0 + min = DEFSLIDERMIN + max = DEFSLIDERMAX + dir = 1 + wxSlider.__init__(self, parentApp.mainFrame.mainPanel, + id, value, min, max, pos, sSize, style) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + EVT_COMMAND_SCROLL(parentApp, self.GetId(), self.eScrolled) + self.lastValue = value + self.setDirection(dir) + self.resetBackground = True + self.setSliderValue(value) + def PDAction(self, value): + try: + num = atof(value) + self.setSliderValue(num) + except: + pass + def setDirection(self, val): + if (val == 0): + self.direction = 0 + else: + self.direction = 1 + def getDirection(self): + return self.direction + def getSliderValue(self): + direction = self.direction + styleFlag = self.GetWindowStyleFlag() + if (((direction) and (styleFlag & wxSL_VERTICAL)) \ + or ((not direction) and (styleFlag & wxSL_HORIZONTAL))): + value = self.GetMax() - self.GetValue() + self.GetMin() + else: + value = self.GetValue() + return value + def setSliderValue(self, num): + if (((self.direction == 1) and (self.GetWindowStyleFlag() \ + & wxSL_VERTICAL)) \ + or ((self.direction == 0) \ + and (self.GetWindowStyleFlag() \ + & wxSL_HORIZONTAL))): + value = self.GetMax() - num + self.GetMin() + else: + value = num + self.SetValue(value) + def GetLabel(self): + return repr(self.getSliderValue()) + def SetLabel(self, value): + try: + self.setSliderValue(atoi(value)) + except: + pass + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Position", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + self.SetForegroundColour(editValues[6]) + self.SetBackgroundColour(editValues[7]) + try: + self.SetRange(atoi(editValues[8]), + atoi(editValues[9])) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Range", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + if (editValues[10] == "Up"): + self.setDirection(1) + elif (editValues[10] == "Down"): + self.setDirection(0) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("Width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("F Color:", + COLOREDITINPUT, + self.GetForegroundColour()) + editor.addEditItem("B Color:", + COLOREDITINPUT, + self.GetBackgroundColour()) + editor.addEditItem("Minimum:", + TEXTEDITINPUT, + self.GetMin()) + editor.addEditItem("Maximum:", + TEXTEDITINPUT, + self.GetMax()) + if (self.getDirection() == 1): + ddValues = ["Up", "Down"] + else: + ddValues = ["Down", "Up"] + editor.addEditItem("Direction:", + DROPDOWNEDITINPUT, + ddValues) + editor.edit() + def eScrolled(self, event): + if (not self.editMode): + value = self.getSliderValue() + if (self.lastValue != value): + self.lastValue = value + self.sendMessage(repr(value)) + +#class for `decorative' rectangle +class mRectangle(mControl, wxStaticBox): + def __init__(self, parentApp, type, id, text, pos, sSym, rSym, conn): + wxStaticBox.__init__(self, parentApp.mainFrame.mainPanel, + id, text, pos, DEFRECTSIZE) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.resetBackground = True + def SetValue(self, value): + self.SetLabel(value) + def eLeftDown(self, event): + if (self.editMode): + if (event.GetPosition()[0] < 20 or \ + event.GetPosition()[1] < 20 or \ + event.GetPosition()[0] > self.GetSize()[0] - 20 or\ + event.GetPosition()[1] > self.GetSize()[1] - 20): + if (event.ControlDown()): + if (self.isSelected()): + self.deselect() + else: + self.select() + else: + self.parentApp.deselectOthers(self.GetId()) + self.select() + else: + self.parentApp.eLeftDown(event) + else: + event.Skip() + + +# Class for `decorative' text +class mText(mControl, wxStaticText): + def __init__(self, parentApp, type, id, text, pos, sSym, rSym, conn): + wxStaticText.__init__(self, parentApp.mainFrame.mainPanel, + id, text, pos, wxDefaultSize, + wxALIGN_CENTRE | wxST_NO_AUTORESIZE) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.resetBackground = True + def SetValue(self, value): + self.SetLabel(value) + self.Refresh() + +#Class for gauges +class mGauge(wxGauge, mSlider): + def __init__(self, parentApp, type, id, label, pos, + style, sSym, rSym, conn): + if (style & wxGA_HORIZONTAL): + size = DEFHGAUGESIZE + else: + size = DEFVGAUGESIZE + if (isinstance(label, list)): + try: + value = atoi(label[0]) + except: + value = 0 + max = label[2] + else: + try: + value = atoi(label) + except: + value = 0 + max = DEFSLIDERMAX + wxGauge.__init__(self, parentApp.mainFrame.mainPanel, + id, max, pos, size, style | wxGA_SMOOTH) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + try: + self.SetValue(value) + except: + pass + def GetMin(self): + return 0 + def GetMax(self): + return self.GetRange() + def SetRange(self, min, max): + wxGauge.SetRange(self, max) + def getDirection(self): + return 0 + def setDirection(self, x): + pass + def GetLabel(self): + return repr(self.GetValue()) + def SetLabel(self, value): + try: + self.SetValue(atoi(value)) + except: + pass + def PDAction(self, value): + try: + num = atof(value) + if (num > self.GetMax()): + num = self.GetMax() + if (num < 0): + num = 0 + self.SetValue(num) + except: + self.SetLabel(value) + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Position", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + try: + self.SetRange(0, + atoi(editValues[6])) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Maximum", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.SetForegroundColour(editValues[7]) + self.SetBackgroundColour(editValues[8]) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("Width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("Maximum:", + TEXTEDITINPUT, + self.GetMax()) + editor.addEditItem("F Color:", + COLOREDITINPUT, + self.GetForegroundColour()) + editor.addEditItem("B Color:", + COLOREDITINPUT, + self.GetBackgroundColour()) + editor.edit() + +# Class for checkboxes +class mCheckBox(wxCheckBox, mToggle): + def __init__(self, parentApp, type, id, text, pos, sSym, rSym, conn): + wxCheckBox.__init__(self, parentApp.mainFrame.mainPanel, + id, text, pos) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.resetBackground = True + EVT_CHECKBOX(parentApp.mainFrame.mainPanel, + self.GetId(), self.eClicked) + +# Class for radio buttons +class mRadioButton(wxRadioButton, mToggle): + def __init__(self, parentApp, type, id, text, + pos, sSym, rSym, style, conn): + wxRadioButton.__init__(self, parentApp.mainFrame.mainPanel, + id, text, pos, wxDefaultSize, style) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.resetBackground = True + EVT_RADIOBUTTON(parentApp.mainFrame.mainPanel, + self.GetId(), self.eClicked) + self.SetValue(False) + def eClicked(self, event): + if (not self.editMode and (self.GetValue() > 0)): + self.sendMessage("bang") + +# Class for textboxes +class mTextBox(mControl, wxTextCtrl): + def __init__(self, parentApp, type, id, label, pos, sSym, rSym, conn): + wxTextCtrl.__init__(self, parentApp.mainFrame.mainPanel, + id, "", pos, wxDefaultSize, + wxTE_PROCESS_ENTER) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.SetValue(label) + EVT_TEXT_ENTER(parentApp.mainFrame.mainPanel, self.GetId(), self.eEnter) + def PDAction(self, value): + if (value == "bang"): + self.SetValue("") + else: + self.SetValue(value) + def GetLabel(self): + return self.GetValue() + def SetLabel(self, value): + self.SetValue(value) + def eEnter(self, event): + value = self.GetValue() + if (not self.editMode): + self.sendMessage(value) + +# Class for spin buttons +class mSpinButton(wxSpinButton, mSlider): + def __init__(self, parentApp, type, id, label, pos, sSym, rSym, conn): + wxSpinButton.__init__(self, parentApp.mainFrame.mainPanel, + id, pos, wxDefaultSize, + wxSP_VERTICAL) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + try: + self.SetValue(atoi(label)) + except: + pass + EVT_SPIN(parentApp.mainFrame.mainPanel, self.GetId(), self.eSpin) + def getDirection(self): + return 0 + def setDirection(self, x): + pass + def PDAction(self, value): + try: + num = atof(value) + if (num > self.GetMax()): + num = self.GetMax() + if (num < 0): + num = 0 + self.SetValue(num) + except: + self.SetLabel(value) + def GetLabel(self): + return repr(self.GetValue()) + def SetLabel(self, value): + try: + self.SetValue(atoi(value)) + except: + pass + def eSpin(self, event): + value = repr(self.GetValue()) + if (not self.editMode): + self.sendMessage(value) + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Position", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + try: + self.SetRange(atoi(editValues[6]), + atoi(editValues[7])) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Range", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.SetForegroundColour(editValues[8]) + self.SetBackgroundColour(editValues[9]) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("Width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("Minimum:", + TEXTEDITINPUT, + self.GetMin()) + editor.addEditItem("Maximum:", + TEXTEDITINPUT, + self.GetMax()) + editor.addEditItem("F Color:", + COLOREDITINPUT, + self.GetForegroundColour()) + editor.addEditItem("B Color:", + COLOREDITINPUT, + self.GetBackgroundColour()) + editor.edit() + +# Class for mouse capture area +class mMouseArea(wxPanel, mControl): + def __init__(self, parentApp, type, id, pos, sSym, rSym, conn): + wxPanel.__init__(self, parentApp.mainFrame.mainPanel, -1, pos, + (DEFMOUSEAREASIZE, DEFMOUSEAREASIZE), wxBORDER) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.mouseCaptured = False + EVT_MIDDLE_DOWN(self, self.eMiddleDown) + EVT_MIDDLE_UP(self, self.eMiddleUp) + EVT_RIGHT_UP(self, self.eRightUp) + def sendMouseInfo(self, xPos, yPos, buttonNum, buttonStatus): + xPosStr = repr(xPos) + yPosStr = repr(yPos) + if (buttonNum > -1): + buttonNumStr = repr(buttonNum) + buttonStatusStr = repr(buttonStatus) + self.sendMessage(xPosStr + " " + \ + yPosStr + " " + \ + buttonNumStr + " " + \ + buttonStatusStr) + else: + self.sendMessage(xPosStr + " " + yPosStr) + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Position", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + self.SetBackgroundColour(editValues[6]) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("Width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("Color:", + COLOREDITINPUT, + self.GetBackgroundColour()) + editor.edit() + def eLeftDown(self, event): + if (self.editMode): + if (event.ControlDown()): + if (self.isSelected()): + self.deselect() + else: + self.select() + else: + self.parentApp.deselectOthers(self.GetId()) + self.select() + else: + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 0, + 1) + event.Skip() + self.eStartCapture(event) + def eRightDown(self, event): + if (self.editMode): + self.parentApp.deselectOthers(self.GetId()) + self.select() + self.eEdit(event) + else: + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 2, + 1) + def eRightUp(self, event): + if (not self.editMode): + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 2, + 0) + def eMiddleDown(self, event): + if (not self.editMode): + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 1, + 1) + def eMiddleUp(self, event): + if (not self.editMode): + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 1, + 0) + def eStartCapture(self, event): + if (not self.mouseCaptured): + self.CaptureMouse() + self.mouseCaptured = True + EVT_LEFT_UP(self, self.eEndCapture) + EVT_MOTION(self, self.eCaptureMouse) + def eEndCapture(self, event): + if (self.mouseCaptured): + self.ReleaseMouse() + self.mouseCaptured = False + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 0, + 0) + self.Disconnect(-1, wxEVT_MOTION) + self.Disconnect(-1, wxEVT_LEFT_UP) + def eCaptureMouse(self, event): + if (event.LeftIsDown() and self.mouseCaptured): + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + -1, + -1) + +class mGraph(wxPanel, mSlider): + def __init__(self, parentApp, type, id, label, pos, sSym, rSym, conn): + wxPanel.__init__(self, parentApp.mainFrame.mainPanel, -1, pos, + (DEFMOUSEAREASIZE, DEFMOUSEAREASIZE), wxSIMPLE_BORDER) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.arrayLength = 0 + self.arrayRawData = [] + self.arrayDrawData = [] + self.min = -1 + self.max = 1 + self.mouseCaptured = False + if (isinstance(label, list)): + try: + value = atoi(label[0]) + except: + value = 0 + self.min = label[1] + self.max = label[2] + aData = label[3] + self.arrayLength = aData[0] + self.arrayRawData = aData[1:] + if (self.arrayLength == 0): + self.arrayLength = 100 + for i in range(0, 100): + self.arrayRawData.append(0) + for i in range(0, self.arrayLength): + drawData = self.getDrawData(i, 0) + self.arrayDrawData.append(drawData) + EVT_PAINT(self, self.ePaint) + def GetMin(self): + return self.min + def GetMax(self): + return self.max + def getDirection(self): + return [self.arrayLength] + self.arrayRawData + def PDAction(self, value): + value = strip(value) + if (lower(value) == "bang"): + self.Refresh() + else: + isAnInt = False + try: + aLen = atoi(value) + isAnInt = True + except: + pass + if (isAnInt): + if (aLen > self.arrayLength): + for i in range(self.arrayLength, aLen): + self.arrayRawData.append(0) + self.arrayDrawData.append(self.getDrawData(i, 0)) + elif (aLen < self.arrayLength): + del self.arrayRawData[aLen:] + del self.arrayDrawData[aLen:] + self.arrayLength = aLen + for i in range(0, self.arrayLength): + self.arrayDrawData[i] = self.getDrawData(i, + self.arrayRawData[i]) + else: + try: + [aIndex, aValue] = split(value, ' ') + aIndex = atoi(aIndex) + aValue = atof(aValue) + if (self.arrayRawData[aIndex] != aValue and \ + aIndex >= 0 and \ + aIndex < self.arrayLength): + self.arrayRawData[aIndex] = aValue + self.arrayDrawData[aIndex] = self.getDrawData(aIndex, + aValue) + except: + pass + self.Refresh() + def getDrawData(self, index, value): + (xSize, ySize) = self.GetSize() + div = float(self.arrayLength - 1) + if (div != 0): + xScale = xSize / div + else: + xScale = 1 + div = float(self.max - self.min) + if (div != 0): + yScale = ySize / div + else: + yScale = 1 + yOffset = int(self.max * yScale) + x = int(xScale * index) + y = yOffset - int(yScale * value) + pnt = (x,y) + return pnt + def setSize(self, size): + self.SetSize(size) + if (self.selected): + self.relocateTags() + for i in range(0, len(self.arrayRawData)): + self.arrayDrawData[i] = self.getDrawData(i, + self.arrayRawData[i]) + self.Refresh() + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Position", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.min = atof(editValues[6]) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Minimum", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.max = atof(editValues[7]) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Maximum", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + self.SetBackgroundColour(editValues[8]) + self.SetForegroundColour(editValues[9]) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("Width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("Minumum:", + TEXTEDITINPUT, + repr(self.min)) + editor.addEditItem("Maximum:", + TEXTEDITINPUT, + repr(self.max)) + editor.addEditItem("B Color:", + COLOREDITINPUT, + self.GetBackgroundColour()) + editor.addEditItem("F Color:", + COLOREDITINPUT, + self.GetForegroundColour()) + editor.edit() + def ePaint(self, event): + event.Skip() + myDC = wxPaintDC(self) + myDC.BeginDrawing() + myDC.SetPen(wxPen(self.GetForegroundColour(), 1, wxSOLID)) + myDC.SetBrush(wxBrush("#000000", wxTRANSPARENT)) + myDC.DrawLines(self.arrayDrawData) + myDC.EndDrawing() + def eDrawMotion(self, event): + if (self.mouseCaptured): + (mouseX, mouseY) = event.GetPosition() + div = float(self.arrayLength - 1) + if (div != 0): + xScale = self.GetSize()[0] / div + else: + xScale = 1 + div = float(self.max - self.min) + if (div != 0): + yScale = self.GetSize()[1] / div + else: + yScale = 1 + yOffset = int(self.max * yScale) + if (xScale != 0): + x = int(mouseX / xScale) + else: + x = 0 + if (yScale != 0): + y = self.max - (mouseY / yScale) + else: + y = 0 + if (x >= 0 and x < self.arrayLength and \ + y >= self.min and y <= self.max): + self.arrayRawData[x] = y + self.arrayDrawData[x] = self.getDrawData(x, y) + self.Refresh() + self.sendMessage(repr(x) + " " + repr(y)) + def eLeftDown(self, event): + if (self.editMode): + if (event.ControlDown()): + if (self.isSelected()): + self.deselect() + else: + self.select() + else: + self.parentApp.deselectOthers(self.GetId()) + self.select() + else: + event.Skip() + self.eStartCapture(event) + def eStartCapture(self, event): + if (not self.mouseCaptured): + self.CaptureMouse() + self.mouseCaptured = True + EVT_LEFT_UP(self, self.eEndCapture) + EVT_MOTION(self, self.eDrawMotion) + def eEndCapture(self, event): + if (self.mouseCaptured): + self.ReleaseMouse() + self.mouseCaptured = False + self.Disconnect(-1, wxEVT_MOTION) + self.Disconnect(-1, wxEVT_LEFT_UP) + def eCaptureMouse(self, event): + pass + +# Class for clickable image +# seems to have problems capturing the mouse? +class mImage(mMouseArea, wxStaticBitmap): + def __init__(self, parentApp, type, id, filepath, + pos, sSym, rSym, conn): + self.filename = filepath + self.image = wxImage(self.filename, + wxBITMAP_TYPE_ANY) + tempBitmap = self.image.ConvertToBitmap() + if (not tempBitmap.Ok()): + raise Exception + wxStaticBitmap.__init__(self, parentApp.mainFrame.mainPanel, id, + tempBitmap, pos, wxDefaultSize) + mControl.__init__(self, parentApp, type, sSym, rSym, conn) + self.resetBackground = True + self.mouseCaptured = False + EVT_LEFT_DOWN(self, self.eLeftDown) + EVT_MIDDLE_DOWN(self, self.eMiddleDown) + EVT_MIDDLE_UP(self, self.eMiddleUp) + EVT_RIGHT_UP(self, self.eRightUp) + def sendMouseInfo(self, xPos, yPos, buttonNum, buttonStatus): + xPosStr = repr(xPos) + yPosStr = repr(yPos) + if (buttonNum > -1): + buttonNumStr = repr(buttonNum) + buttonStatusStr = repr(buttonStatus) + self.sendMessage(xPosStr + " " + \ + yPosStr + " " + \ + buttonNumStr + " " + \ + buttonStatusStr) + else: + self.sendMessage(xPosStr + " " + yPosStr) + def resize(self, deltaPos): + if (self.editMode): + xSize = self.GetSize()[0] + deltaPos[0] + ySize = self.GetSize()[1] + deltaPos[1] + if (xSize > 0 and ySize > 0): + if (xSize <= self.image.GetWidth() and + ySize <= self.image.GetHeight()): + self.setSize((xSize, ySize)) + elif (xSize <= self.image.GetWidth()): + self.setSize((xSize, self.GetSize()[1])) + elif (ySize <= self.image.GetHeight()): + self.setSize((self.GetSize()[0], ySize)) + def setSize(self, size): + self.SetSize(size) + if (self.selected): + self.relocateTags() + newImage = self.image.GetSubImage((0,0,size[0],size[1])) + newBitmap = newImage.ConvertToBitmap() + self.SetBitmap(newBitmap) + def setEditMode(self, mode): + if (mode): + if (not self.editMode): + EVT_RIGHT_DOWN(self, self.eRightDown) + self.moveTag = controlEditTag(self, + (0,0), + wxBLACK, + wxCURSOR_CROSS) + self.BLResizeTag = controlResizeTag(self, + (1,0), + RESIZETAGCOLOR, + wxCURSOR_SIZEWE) + self.TRResizeTag = controlResizeTag(self, + (0,1), + RESIZETAGCOLOR, + wxCURSOR_SIZENS) + self.BRResizeTag = controlResizeTag(self, + (1,1), + RESIZETAGCOLOR, + wxCURSOR_SIZENWSE) + self.editMode = True + else: + if (self.editMode): + self.Disconnect(-1, wxEVT_RIGHT_DOWN) + self.deselect() + self.moveTag.Destroy() + self.BLResizeTag.Destroy() + self.TRResizeTag.Destroy() + self.BRResizeTag.Destroy() + self.editMode = False + def Refresh(self): + if (self.filename != self.GetLabel()): + self.SetLabel(self.filename) + wxStaticBitmap.Refresh(self) + wxYield() + self.parentApp.mainFrame.mainPanel.Refresh() + def SetLabel(self, label): + self.filename = label + self.image = wxImage(self.filename, + wxBITMAP_TYPE_ANY) + tempBitmap = self.image.ConvertToBitmap() + self.SetBitmap(tempBitmap) + self.setSize((self.image.GetWidth(), self.image.GetHeight())) + wxStaticBitmap.Refresh(self) + self.parentApp.mainFrame.mainPanel.Refresh() + def GetLabel(self): + return self.filename + def PDAction(self, value): + if (value[0:4] == "hide"): + self.Show(False) + # self.parentApp.mainFrame.mainPanel.Refresh() + elif (value[0:4] == "show"): + self.Show(True) + # self.parentApp.mainFrame.mainPanel.Refresh() + elif (value[0:6] == "rotate"): + theta = atof(value[6:len(value)]) * math.pi / 180 + tempImage = wxImage(self.filename,wxBITMAP_TYPE_ANY) + bgColor = self.parentApp.mainFrame.mainPanel.GetBackgroundColour() + tempImage.SetMaskColour(bgColor.Red(), + bgColor.Green(), + bgColor.Blue()) + rotateImage = tempImage.Rotate(theta, (0,0), True) + bgColor = self.parentApp.mainFrame.mainPanel.GetBackgroundColour() + self.SetBitmap(rotateImage.ConvertToBitmap()) + wxStaticBitmap.Refresh(self) + self.parentApp.mainFrame.mainPanel.Refresh() + else: + if (value[0:2] == "./" or + value[0:3] == "../"): + value = scrubPath(self.parentApp.filepath + value) + self.SetLabel(value) + def editCallback(self, editValues): + try: + self.setPosition((atoi(editValues[0]), atoi(editValues[1]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + try: + self.setSize(wxSize(atoi(editValues[2]), atoi(editValues[3]))) + except: + dlg = wxMessageDialog(self.parentApp.mainFrame, + "Invalid Size", + "Edit Error", + wxOK) + dlg.ShowModal() + dlg.Destroy() + self.setSendSymbol(editValues[4]) + self.setReceiveSymbol(editValues[5]) + self.SetLabel(editValues[6]) + def eEdit(self, event): + editor = controlEditor(self) + editor.addEditItem("X Position:", + TEXTEDITINPUT, + self.GetPosition()[0]) + editor.addEditItem("Y Position:", + TEXTEDITINPUT, + self.GetPosition()[1]) + editor.addEditItem("width:", + TEXTEDITINPUT, + self.GetSize()[0]) + editor.addEditItem("Height:", + TEXTEDITINPUT, + self.GetSize()[1]) + editor.addEditItem("S Symbol:", + TEXTEDITINPUT, + self.getSendSymbol()) + editor.addEditItem("R Symbol:", + TEXTEDITINPUT, + self.getReceiveSymbol()) + editor.addEditItem("File:", + FILEEDITINPUT, + self.GetLabel()) + editor.edit() + def eStartCapture(self, event): + if (not self.mouseCaptured): + self.mouseCaptured = True + EVT_LEFT_UP(self, self.eEndCapture) + EVT_MOTION(self, self.eCaptureMouse) + def eEndCapture(self, event): + if (self.mouseCaptured): + self.mouseCaptured = False + self.sendMouseInfo(event.GetPosition()[0], + event.GetPosition()[1], + 0, + 0) + self.Disconnect(-1, wxEVT_MOTION) + self.Disconnect(-1, wxEVT_LEFT_UP) + +class editItem: + def __init__(self, title, dataType, value): + self.title = title + self.dataType = dataType + self.value = value + def setValue(self, value): + self.value = value + +class editSetButton(wxButton): + def __init__(self, parent, position, size, value): + wxButton.__init__(self, parent, -1, "Set", position, size) + self.parent = parent + self.value = value + EVT_BUTTON(parent, self.GetId(), self.eClick) + def GetValue(self): + return self.value + +class editSetFontButton(editSetButton): + def eClick(self, event): + self.value = getFontFromDialog(self.parent, self.value) + +class editSetColorButton(editSetButton): + def eClick(self, event): + self.value = getColorFromDialog(self.parent, self.value) + +class editSetFileButton(editSetButton): + def eClick(self, event): + tempFile = getFileFromDialog(self.parent, self.value) + if (tempFile): + self.value = tempFile + +class editDropdown(wxComboBox): + def __init__(self, parent, position, size, values): + wxComboBox.__init__(self, + parent, + -1, + values[0], + position, + size, + values, + wxCB_READONLY) + self.parent = parent + +class controlEditor: + def __init__(self, control): + self.control = control + self.editItems = [] + self.valueControls = [] + def addEditItem(self, title, dataType, value): + self.editItems.append(editItem(title, dataType, value)) + def edit(self): + global lastEditWindowPosition + if (lastEditWindowPosition == (-1, -1)): + lastEditWindowPosition = ( \ + self.control.parentApp.mainFrame.GetPosition()[0] + 20, + self.control.parentApp.mainFrame.GetPosition()[1] + 20) + self.editFrame = wxMiniFrame(self.control, + -1, + "Edit Control", + lastEditWindowPosition, + (100, 200), + wxCAPTION | wxSTAY_ON_TOP) + self.editFrame.editPanel = wxPanel(self.editFrame, -1, (0,0), (-1, -1)) + labels = [] + self.valueControls = [] + count = 0 + newLabel = wxStaticText(self.editFrame.editPanel, + -1, + self.editItems[0].title, + DEFEDITPOS) + labels.append(newLabel) + if (type(self.editItems[0].value) == type(0)): + value = repr(self.editItems[0].value) + else: + value = self.editItems[0].value + if (self.editItems[0].dataType == TEXTEDITINPUT): + newControl = wxTextCtrl(self.editFrame.editPanel, + -1, + value, + (labels[0].GetPosition()[0] \ + + 65, + labels[0].GetPosition()[1] - 2), + (60,-1)) + if (self.editItems[0].dataType == FONTEDITINPUT): + newControl = editSetFontButton(self.editFrame.editPanel, + (labels[0].GetPosition()[0] + 65, + labels[0].GetPosition()[1] - 2), + (60, -1), + self.editItems[0].value) + if (self.editItems[0].dataType == COLOREDITINPUT): + newControl = editSetColorButton(self.editFrame.editPanel, + (labels[0].GetPosition()[0] + 65, + labels[0].GetPosition()[1] - 2), + (60, -1), + self.editItems[0].value) + if (self.editItems[0].dataType == FILEEDITINPUT): + newControl = editSetFileButton(self.editFrame.editPanel, + (labels[0].GetPosition()[0] + 65, + labels[0].GetPosition()[1] - 2), + (60, -1), + self.editItems[0].value) + if (self.editItems[0].dataType == DROPDOWNEDITINPUT): + newControl = editDropdown(self.editFrame.editPanel, + labels[0].GetPosition()[0] + 65, + labels[0].GetPosition()[1] - 2, + (60, -1), + self.editItems[0].value) + self.valueControls.append(newControl) + for i in self.editItems[1:]: + count = count + 1 + if (type(i.value) == type(0)): + value = repr(i.value) + else: + value = i.value + newLabel = wxStaticText(self.editFrame.editPanel, + -1, + i.title, + (labels[count - 1].GetPosition()[0], + self.valueControls[count - 1].GetPosition()[1] \ + + self.valueControls[count - 1].GetSize()[1] + 10)) + labels.append(newLabel) + if (i.dataType == TEXTEDITINPUT): + newControl = wxTextCtrl(self.editFrame.editPanel, + -1, + value, + (self.valueControls[count - 1].GetPosition()[0], + labels[count].GetPosition()[1] - 2), + self.valueControls[count - 1].GetSize()) + if (self.editItems[count].dataType == FONTEDITINPUT): + newControl = editSetFontButton(self.editFrame.editPanel, + (self.valueControls[count - 1].GetPosition()[0], + labels[count].GetPosition()[1] - 2), + self.valueControls[count - 1].GetSize(), + self.editItems[count].value) + if (self.editItems[count].dataType == COLOREDITINPUT): + newControl = editSetColorButton(self.editFrame.editPanel, + (self.valueControls[count - 1].GetPosition()[0], + labels[count].GetPosition()[1] - 2), + self.valueControls[count - 1].GetSize(), + self.editItems[count].value) + if (self.editItems[count].dataType == FILEEDITINPUT): + newControl = editSetFileButton(self.editFrame.editPanel, + (self.valueControls[count - 1].GetPosition()[0], + labels[count].GetPosition()[1] - 2), + self.valueControls[count - 1].GetSize(), + self.editItems[count].value) + if (self.editItems[count].dataType == DROPDOWNEDITINPUT): + newControl = editDropdown(self.editFrame.editPanel, + (self.valueControls[count - 1].GetPosition()[0], + labels[count].GetPosition()[1] - 2), + self.valueControls[count - 1].GetSize(), + self.editItems[count].value) + self.valueControls.append(newControl) + line = wxStaticLine(self.editFrame.editPanel, -1, + (0, self.valueControls[-1].GetPosition()[1] \ + + self.valueControls[-1].GetSize()[1] + 20), + (self.valueControls[0].GetPosition()[0] \ + + self.valueControls[0].GetSize()[0] + 10, 1)) + okButton = wxButton(self.editFrame.editPanel, -1, "OK", + (labels[0].GetPosition()[0], + line.GetPosition()[1] + 15), + (self.valueControls[0].GetPosition()[0] \ + + self.valueControls[0].GetSize()[0], -1)) + self.editFrame.SetSize((okButton.GetPosition()[0] + \ + okButton.GetSize()[0] + 10, + okButton.GetPosition()[1] + okButton.GetSize()[1] \ + + (okButton.GetPosition()[1] - line.GetPosition()[1]) \ + + 20)) + self.editFrame.editPanel.SetSize(self.editFrame.GetSize()) + EVT_BUTTON(self.editFrame.editPanel, + okButton.GetId(), + self.eOk) + self.editFrame.Show(True) + self.editFrame.MakeModal(True) + def eOk(self, event): + global lastEditWindowPosition + returnValues = [] + for i in range(0, len(self.valueControls)): + returnValues.append(self.valueControls[i].GetValue()) + lastEditWindowPosition = self.editFrame.GetPosition() + self.editFrame.MakeModal(False) + self.editFrame.Destroy() + self.control.editCallback(returnValues) + diff --git a/gripdFunctions.py b/gripdFunctions.py new file mode 100644 index 0000000..2bf0a55 --- /dev/null +++ b/gripdFunctions.py @@ -0,0 +1,191 @@ +## GrIPD v0.1.1 - Graphical Interface for Pure Data +## Copyright (C) 2003 Joseph A. Sarlo +## +## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## jsarlo@ucsd.edu + +from wxPython.wx import * +from string import * +import os +import sys + +VERSION = "0.1.1" +MAXDEC = 9 +DECTOHEXOFFSET = 87 +EVT_RAISE_TAGS_ID = wxNewId() + +debugFile = sys.stderr + +def setDebugFile(filename): + global debugFile + if (filename != ""): + debugFile = open(filename, "w", -1) + +def debugLog(logString): + debugFile.write(logString + "\n") + debugFile.flush() + +def getColorFromDialog(parent, initColor): + colorData = wxColourData() + colorData.SetColour(initColor) + colorData.SetCustomColour(0, initColor) + colorDialog = wxColourDialog(parent, colorData) + colorDialog.ShowModal() + colorData = colorDialog.GetColourData() + return colorData.GetColour() + +def getFontFromDialog(parent, initFont): + fontData = wxFontData() + fontData.SetInitialFont(initFont) + fontDialog = wxFontDialog(parent, fontData) + fontDialog.ShowModal() + fontData = fontDialog.GetFontData() + return fontData.GetChosenFont() + +def getFileFromDialog(parent, initFile): + if (initFile == ""): + initFile = parent.parentApp.filepath + fileDialog = wxFileDialog(parent, + "Open file", + getDirectory(initFile), + initFile, + "*.*", + wxOPEN) + if (fileDialog.ShowModal() == wxID_OK): + return fileDialog.GetPath() + else: + return "" + +def colorTuple2HexString(tuple): + def dec2HexString(value): + if (value > MAXDEC): + return chr(value + DECTOHEXOFFSET) + else: + return repr(value) + hexString = "" + for i in range(0, 3): + hexString = hexString + dec2HexString(int(round(tuple[i] / 16))) + hexString = hexString + dec2HexString(int(round(tuple[i] \ + - (int(tuple[i] / 16) * 16)))) + return hexString + +def selectIntersect(rect1, rect2): + left1 = rect1[0] + top1 = rect1[1] + right1 = rect1[0] + rect1[2] + bottom1 = rect1[1] + rect1[3] + left2 = rect2[0] + top2 = rect2[1] + right2 = rect2[0] + rect2[2] + bottom2 = rect2[1] + rect2[3] + if ((left1 < left2) and (right1 > right2) + and (top1 < top2) and (bottom1 > bottom2)): + return False + if (((left2 > left1) and (left2 < right1)) + or ((right2 > left1) and (right2 < right1)) + or ((left2 < left1) and (right2 > right1))): + if ((top2 > top1) and (top2 < bottom1)): + return True + elif ((bottom2 >top1) and (bottom2 < bottom1)): + return True + elif ((top2 < top1) and (bottom2 > bottom1)): + return True + return False + +def getDirectory(path): + if (os.name == "posix"): + index = rfind(path, "/") + if (index > -1): + tempPath = path[0:index] + while (tempPath[len(tempPath) - 1] == "/"): + tempPath = tempPath[0:len(tempPath) - 1] + tempPath = tempPath + "/" + else: + tempPath = "" + else: + index = max(rfind(path, "\\"), rfind(path, "/")) + if (index > -1): + tempPath = path[0:index] + while (tempPath[len(tempPath) - 1] == "/" or + tempPath[len(tempPath) - 1] == "\\"): + tempPath = tempPath[0:len(tempPath) - 1] + tempPath = tempPath + "\\" + else: + tempPath = "" + return tempPath + +def replaceSlashes(path): + path = replace(path, "/", "\\") + return path + +def scrubPath(path): + if (os.name == "posix"): + while (find(path, "/../") > 0): + index = rfind(path[0:find(path, "/../")], "/") + path = path[0:index] + path[find(path, "/../") + 3:len(path)] + while (find(path, "/./") > 0): + index = find(path, "/./") + path = path[0:index] + path[index + 2:len(path)] + path = replace(path, "//", "/") + else: + path = replaceSlashes(path) + while (find(path, "\\..\\") > 0): + index = rfind(path[0:find(path, "\\..\\")], "\\") + path = path[0:index] + path[find(path, "\\..\\") + 3:len(path)] + while (find(path, "\\.\\") > 0): + index = find(path, "\\.\\") + path = path[0:index] + path[index + 2:len(path)] + path = replace(path, "\\\\", "\\") + return path + +def makeAbsolutePath(superPath, subPath): + if (os.name == "posix"): + if (find(subPath, "./") == 0 or + find(subPath, "../") == 0): + tempPath = superPath + subPath + elif (subPath[0] != "/"): + tempPath = superPath + "/" + subPath + else: + tempPath = subPath + else: + if (find(subPath, "/") >= 0): + subPath = replaceSlashes(subPath) + if (find(subPath, ".\\") == 0 or + find(subPath, "..\\") == 0): + tempPath = superPath + subPath + elif (subPath[1] != ":"): + tempPath = superPath + "\\" + subPath + else: + tempPath = subPath + return scrubPath(tempPath) + +def makeRelativePath(superPath, subPath): + if (os.name != "posix"): + superPath = lower(superPath) + subPath = lower(subPath) + if (find(subPath, superPath) == 0 and superPath != ""): + tempPath = "./" + subPath[len(superPath):len(subPath)] + else: + tempPath = subPath + return scrubPath(tempPath) + + +class RaiseTagsEvent(wxPyEvent): + def __init__(self): + wxPyEvent.__init__(self) + self.SetEventType(EVT_RAISE_TAGS_ID) + + diff --git a/gripdMain.py b/gripdMain.py new file mode 100644 index 0000000..1e20cb5 --- /dev/null +++ b/gripdMain.py @@ -0,0 +1,2337 @@ +## GrIPD v0.1.1 - Graphical Interface for Pure Data +## Copyright (C) 2003 Joseph A. Sarlo +## +## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## jsarlo@ucsd.edu + +from wxPython.wx import * +from gripdControls import * +from gripdFunctions import * +from socket import * +from string import * + +midi = 0 +joystick = 0 +DEFMAINFRAMESIZE = (600, 400) +DEFCONTROLPOS = (20,20) +ID_ABOUT = 100 +ID_EXIT = 101 +ID_ADD = 102 +ID_EDITMODE = 103 +ID_EDIT = 104 +ID_DELETE = 105 +ID_CONNECT = 106 +ID_OPEN = 107 +ID_SAVE = 108 +ID_OPTIONS = 109 +ID_BUTTONMENU = 110 +ID_SLIDERMENU = 111 +ID_GAUGEMENU = 112 +ID_SELECTALL = 113 +ID_NEW = 114 +ID_DUPLICATE = 115 +ID_ALIGNVERT = 116 +ID_ALIGNHORZ = 117 +ID_REFRESH = 118 +ID_BUTTON = 200 +ID_TOGGLE = 201 +ID_VSLIDER = 202 +ID_HSLIDER = 203 +ID_RECT = 204 +ID_TEXT = 205 +ID_SETOPTS = 206 +ID_DISCONNECT = 207 +ID_VGAUGE = 208 +ID_HGAUGE = 209 +ID_CHECKBOX = 210 +ID_TEXTBOX = 211 +ID_SPINBUTTON = 212 +ID_MOUSEAREA = 213 +ID_ENABLEJOY = 214 +ID_ENABLEKEY = 215 +ID_LOCKONPERF = 216 +ID_RADIOBUTTON = 217 +ID_IMAGE = 218 +ID_ALWAYSONTOP = 219 +ID_SHOWGRID = 220 +ID_SNAPTOGRID = 221 +ID_ENABLEMIDI = 222 +ID_GRAPH = 223 +COMMANDCHAR = '!' +DEFHOST = 'localhost' +DEFPORT = 3490 +CONNECTINTERVAL = 1000 +TIMEOUT = 20 +HIDECOMMAND = "!hide" +SHOWCOMMAND = "!show" +EXITCOMMAND = "!exit" +LOCKCOMMAND = "!lock" +UNLOCKCOMMAND = "!unlock" +SETTITLECOMMAND = "!settitle" +CLOSECOMMAND = "!disconnect" +PINGCOMMAND = "!ping" +OPENPANELCOMMAND = "!openpanel" +SAVEPANELCOMMAND = "!savepanel" +BEGINCONTROLMARKER = "!BEGIN-CONTROL" +ENDCONTROLMARKER = "!END-CONTROL" +DEFOPTIONSPOS = (5, 5) +DUPPOSOFFSET = (10, 10) +SMALLCHARMOVE = 1 +LARGECHARMOVE = 20 +BGCOLORDIF = 30 +DEFSOCKETTIMERTIME = 5 +DEFJOYPOLLTIME = 10 +DEFMIDIPOLLTIME = 5 +DEFMIDIDEVICE1 = 0 +DEFMIDIDEVICE2 = 1 +PAIRSEPCHAR = chr(29) +SYMMSGSEP = chr(31) +FILETOKENSEP = "|" +MAXPINGCOUNT = 10 +PINGPOLLTIME = 1000 +MIDINOTEMESSAGE = "9" +MIDICTLMESSAGE = "b" +MIDIPGMMESSAGE = "c" +SETARRAYSTRING = "!setArray" + +if (os.name == "posix"): + FUGEFACTOR = 1 + DEFJOYDEVICE1 = "/dev/js0" + DEFJOYDEVICE2 = "/dev/js1" +else: + FUGEFACTOR = 2 + DEFJOYDEVICE1 = "1" + DEFJOYDEVICE2 = "2" + +# Main application class +class mainApp(wxPySimpleApp): + def __init__(self, args): + self.args = args + wxApp.__init__(self, False) + try: + wxLog_SetLogLevel(0) + except: + pass + def OnInit(self): + global midi + global joystick + openAuto = False + newPort = 0 + filename = "" + locked = False + self.path = scrubPath(getDirectory(self.args[0])) + setDebugFile(self.path + "/log.txt") + self.filepath = "" + if (len(self.args) > 1): + filename = self.args[1] + self.filepath = getDirectory(filename) + if (self.filepath == ""): + self.filepath = self.path + self.filepath = makeAbsolutePath(self.path, self.filepath) + if (len(self.args) > 2): + newPort = atoi(self.args[2]) + if (len(self.args) > 3): + openAuto = atoi(self.args[3]) + if (len(self.args) > 4): + locked = atoi(self.args[4]) + self.midiAvailable = True + self.joystickAvailable = True + try: + optionsFile = open(self.path + "/gripd.opt", 'r', -1) + options = optionsFile.readlines() + for option in options: + [key, value] = split(option, '=') + key = strip(key) + value = strip(value) + if (lower(key) == 'midi'): + if (lower(value) == 'false'): + self.midiAvailable = False + if (lower(key) == 'joystick'): + if (lower(value) == 'false'): + self.joystickAvailable = False + except: + pass + if (self.midiAvailable): + import midi + if (self.joystickAvailable): + import joystick + wxInitAllImageHandlers() + if (not os.name == "posix"): + self.icon = wxIcon(self.path + "icon.pic", wxBITMAP_TYPE_ICO) + self.jsImage = wxImage(self.path + "joystick.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.jsImageX = wxImage(self.path + "joystickX.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.jsImageA = wxImage(self.path + "joystickA.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.midiImage = wxImage(self.path + "midi.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.midiImageX = wxImage(self.path + "midiX.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.midiImageA = wxImage(self.path + "midiA.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.connectImage = wxImage(self.path + "connect.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.connectImageX = wxImage(self.path + "connectX.xpm", + wxBITMAP_TYPE_XPM).ConvertToBitmap() + self.editMode = False + # socket stuff + self.host = DEFHOST + self.port = DEFPORT + self.connection = nullConnection() + self.connected = False + # All controls (on mainPanel) + self.controlList = [] + # Selected controls, Should speed up editing + # DO NOT use to loop through selected controls to deselect + # .deselect() modifies selectedControlList + self.selectedControlList = [] + # If currently using selecting with selectRect + self.selecting = False + # If currently dragging a control + self.dragging = False + # Keys currently depressed + self.keysDown = [] + # If left mouse was clicked on panel + # not on control or tag, for selectRect + self.leftDownOnPanel = False + # If current GUI has been changed since last save + self.edited = False + # control counters (for send/receive syms) + self.resetControlIndecies() + # timer to check connection status + self.pTimer = pingTimer(self) + # set ping count + self.pingCount = 0 + # timer to poll for connections + self.cTimer = connectionTimer(self) + # socket polling time + self.pollTime = DEFSOCKETTIMERTIME + # timer to poll socket for receive messages + self.sTimer = socketTimer(self) + # timer to poll joystick + self.joyTimer = joystickTimer(self) + # joystick poll time + self.joyPollTime = DEFJOYPOLLTIME + # joystick device string + self.joyDevice1 = DEFJOYDEVICE1 + self.joyDevice2 = DEFJOYDEVICE2 + # joystick device id + self.joyID1 = -1 + self.joyID2 = -1 + # joystick on + self.joystickEnabled = False + self.jsOn1 = False + self.jsOn2 = False + # timer to poll midi + self.midiTimer = midiTimer(self) + # midi poll time + self.midiPollTime = DEFMIDIPOLLTIME + # midi device numbers + self.midiDevice1 = DEFMIDIDEVICE1 + self.midiDevice2 = DEFMIDIDEVICE2 + # midi device id + self.midiID1 = -1 + self.midiID2 = -1 + # midi on + self.midiEnabled = False + self.midiOn1 = False + self.midiOn2 = False + # send keystrokes + self.sendKeys = True + # grid sized + self.gridSpace = 10 + # display grid + self.showGrid = False + # snap moved controls to grid + self.snapToGrid = False + # locked or unlocked GUI + self.locked = locked + self.openAuto = openAuto + self.frameTitle = "GrIPD" + self.alwaysOnTop = False + self.resizable = False + self.mainFrame = gripdFrame(self, -1, self.frameTitle, + (-1, -1), + self.resizable, self.locked, + self.alwaysOnTop) + self.SetTopWindow(self.mainFrame) + # for catching keystokes + EVT_CHAR(self.mainFrame.mainPanel, self.eChar) + EVT_KEY_UP(self.mainFrame.mainPanel, self.eKeyUp) + EVT_KEY_DOWN(self.mainFrame.mainPanel, self.eKeyDown) + if (not os.name == "posix"): + EVT_CHAR_HOOK(self.mainFrame, self.eChar) + EVT_CLOSE(self.mainFrame, self.eClose) + EVT_SIZE(self.mainFrame, self.eSize) + self.mainFrame.positionIcons() + if ((filename != "0") and (filename != "")): + self.openFromDisk(filename) + if (newPort): + self.port = newPort + if (self.openAuto): + self.connect() + else: + self.mainFrame.Show(True) + return True + +## Functions ## + + def createControl(self, type, tIndex, tString, filepath = ""): + if (self.editMode and not self.dragging): + indexStr = tString + repr(tIndex) + clientMousePos = self.mainFrame.mainPanel.ScreenToClient( \ + wxGetMousePosition()) + coords = (clientMousePos[0] + 4, clientMousePos[1] + 4) + control = self.addControl(type, indexStr, coords, + "s" + indexStr, "r" + indexStr, filepath) + control.select() + # I'm not sure why this is necessary + try: + wxYield() + except: + pass + control.grab() + def addControl(self, type, label, pos, sSym, rSym, filepath = ""): + tControl = NULL + if (type == MBUTTONTYPE): + self.buttonIndex = self.buttonIndex + 1 + tControl = mButton(self, type, -1, + label, pos, sSym, rSym, self.connection) + if (type == MTOGGLETYPE): + self.toggleIndex = self.toggleIndex + 1 + tControl = mToggle(self, type, -1, + label, pos, sSym, rSym, self.connection) + if (type == MVSLIDERTYPE): + self.sliderIndex = self.sliderIndex + 1 + tControl = mSlider(self, type, -1, label, pos, + wxSL_VERTICAL, sSym, rSym, self.connection) + if (type == MHSLIDERTYPE): + self.sliderIndex = self.sliderIndex + 1 + tControl = mSlider(self, type, -1, label, pos, + wxSL_HORIZONTAL, sSym, rSym, self.connection) + if (type == MRECTTYPE): + self.rectIndex = self.rectIndex + 1 + tControl = mRectangle(self, type, -1, + label, pos, sSym, rSym, self.connection) + if (type == MTEXTTYPE): + self.textIndex = self.textIndex + 1 + tControl = mText(self, type, -1, + label, pos, sSym, rSym, self.connection) + if (type == MVGAUGETYPE): + self.gaugeIndex = self.gaugeIndex + 1 + tControl = mGauge(self, type, -1, label, pos, + wxGA_VERTICAL, sSym, rSym, self.connection) + if (type == MHGAUGETYPE): + self.gaugeIndex = self.gaugeIndex + 1 + tControl = mGauge(self, type, -1, label, pos, + wxGA_HORIZONTAL, sSym, rSym, self.connection) + if (type == MCHECKBOXTYPE): + self.checkBoxIndex = self.checkBoxIndex + 1 + tControl = mCheckBox(self, type, -1, + label, pos, sSym, rSym, self.connection) + if (type == MRADIOBUTTONTYPE): + self.radioButtonIndex = self.radioButtonIndex + 1 + tControl = mRadioButton(self, type, -1, + label, pos, sSym, rSym, 0, self.connection) + if (type == MRADIONEWTYPE): + self.radioButtonIndex = self.radioButtonIndex + 1 + tControl = mRadioButton(self, type, -1, + label, pos, sSym, rSym, wxRB_GROUP, + self.connection) + if (type == MTEXTBOXTYPE): + self.textBoxIndex = self.textBoxIndex + 1 + tControl = mTextBox(self, type, -1, label, + pos, sSym, rSym, self.connection) + if (type == MSPINBUTTONTYPE): + self.spinButtonIndex = self.spinButtonIndex + 1 + tControl = mSpinButton(self, type, -1, label, + pos, sSym, rSym, self.connection) + if (type == MMOUSEAREATYPE): + self.mouseAreaIndex = self.mouseAreaIndex + 1 + tControl = mMouseArea(self, type, -1, + pos, sSym, rSym, self.connection) + if (type == MIMAGETYPE): + if (filepath == ""): + filepath = label + filepath = makeAbsolutePath(self.filepath, filepath) + self.imageIndex = self.imageIndex + 1 + try: + tControl = mImage(self, type, -1, + filepath, pos, sSym, rSym, self.connection) + except: + tControl = NULL + if (type == MGRAPHTYPE): + self.graphIndex = self.graphIndex + 1 + tControl = mGraph(self, type, -1, label, pos, sSym, + rSym, self.connection) + if (tControl != NULL): + self.controlList.append(tControl) + return (tControl) + def findControlByID(self, id): + for control in self.controlList: + if (control.GetId() == id): + return(control) + def startMoveControls(self): + for control in self.selectedControlList: + control.startMove() + def moveSelectedControls(self, deltaPos): + self.edited = True + for control in self.selectedControlList: + control.move(deltaPos) + def endMoveControls(self): + for control in self.selectedControlList: + control.endMove() + def endDragMoveControls(self): + for control in self.selectedControlList: + control.endDragMove() + def resizeSelectedControls(self, deltaPos): + self.edited = True + for control in self.selectedControlList: + control.resize(deltaPos) + def moveKey(self, deltaPos): + self.moveSelectedControls(deltaPos) + for control in self.selectedControlList: + control.endMove() + def alignControls(self, dir): + otherDir = 1 - dir + alignVal = 1 + alignPos = [0, 0] + for control in self.selectedControlList: + alignVal = max(alignVal, control.GetPosition()[dir]) + alignPos[dir] = alignVal + for control in self.selectedControlList: + alignPos[otherDir] = control.GetPosition()[otherDir] + control.setPosition(alignPos) + def deselectOthers(self, calledByID): + # Not using selectedControlList since we are removing from it + # as we cycle through the list + for control in self.controlList: + if ((control.GetId() != calledByID) and control.isSelected()): + control.deselect() + def raiseControlTags(self): + if (self.editMode): + for control in self.selectedControlList: + control.relocateTags() + control.refreshTags() + def traverseFocus(self, multi): + if ((len(self.controlList) > 0) and (self.editMode)): + i = -1 + newIndex = 0 + for control in self.controlList: + i = i + 1 + if (control.isSelected()): + newIndex = i + 1 + newIndex = newIndex % len(self.controlList) + self.controlList[newIndex].select() + if (not multi): + self.deselectOthers(self.controlList[newIndex].GetId()) + def parseReceiveBuffer(self, receiveBuffer): + # remove trailing PAIRSEPCHAR + receiveBuffer = receiveBuffer[0:-1] + messagePairs = split(receiveBuffer, PAIRSEPCHAR) + for pair in messagePairs: + (symName, value) = split(pair, SYMMSGSEP) + if (symName[0] == COMMANDCHAR): + if (symName == CLOSECOMMAND): + self.disconnect() + dlg = wxMessageDialog(self.mainFrame, + "Connection closed by PD", + "Connection", wxOK) + dlg.ShowModal() + dlg.Destroy() + if (symName == EXITCOMMAND): + self.close() + elif (symName == LOCKCOMMAND): + self.lock() + elif (symName == UNLOCKCOMMAND): + self.unlock() + elif (symName == SETTITLECOMMAND): + self.frameTitle = value + self.setFrameTitle(value) + elif (symName == HIDECOMMAND): + self.mainFrame.Show(False) + self.connection.send(HIDECOMMAND + \ + SYMMSGSEP + "0" + \ + PAIRSEPCHAR) + elif (symName == SHOWCOMMAND): + self.mainFrame.Show(True) + self.connection.send(SHOWCOMMAND + \ + SYMMSGSEP + "0" + \ + PAIRSEPCHAR) + elif (symName == PINGCOMMAND): + self.pingCount = 0 + elif (symName == OPENPANELCOMMAND): + self.mainFrame.openpanel() + elif (symName == SAVEPANELCOMMAND): + self.mainFrame.savepanel() + else: + for control in self.controlList: + if (symName == control.getReceiveSymbol()): + control.PDAction(value) + def writeControls(self, list, file): + for control in list: + file.write(repr(control.getType()) + "\n") + if (control.type == MIMAGETYPE): + file.write(makeRelativePath(self.filepath, + control.GetLabel()) + "\n") + else: + file.write(control.GetLabel() + "\n") + file.write(repr(control.GetPosition()[0]) + "\n") + file.write(repr(control.GetPosition()[1]) + "\n") + file.write(repr(control.GetSize()[0]) + "\n") + file.write(repr(control.GetSize()[1]) + "\n") + file.write(control.getSendSymbol() + "\n") + file.write(control.getReceiveSymbol() + "\n") + if (control.GetBackgroundColour().Ok()): + file.write("#" + colorTuple2HexString((control.\ + GetBackgroundColour().Red(), + control.\ + GetBackgroundColour().Green(), + control.\ + GetBackgroundColour().Blue()))\ + + "\n") + else: + file.write("#00000\n") + if (control.GetForegroundColour().Ok()): + file.write("#" + colorTuple2HexString((control.\ + GetForegroundColour().Red(), + control.\ + GetForegroundColour().Green(), + control.\ + GetForegroundColour().Blue()))\ + + "\n") + else: + file.write("#000000\n") + if (not control.GetFont().Ok()): + control.SetFont(wxNORMAL_FONT) + file.write(repr(control.GetFont().GetPointSize()) + "\n") + file.write(repr(control.GetFont().GetFamily()) + "\n") + file.write(repr(control.GetFont().GetStyle()) + "\n") + file.write(repr(control.GetFont().GetWeight()) + "\n") + file.write(repr(control.GetFont().GetUnderlined()) + "\n") + file.write(control.GetFont().GetFaceName() + "\n") + if (isinstance(control, mSlider)): + file.write(repr(control.GetMin()) + "\n") + file.write(repr(control.GetMax()) + "\n") + file.write(repr(control.getDirection()) + "\n") + file.write(ENDCONTROLMARKER + "\n") + def readControls(self, list): + newList = [] + for i in range(0, list.count(ENDCONTROLMARKER)): + params = list[0:list.index(ENDCONTROLMARKER)] + type = atoi(params[0]) + label = params[1] + pos = (atoi(params[2]), atoi(params[3])) + size = (atoi(params[4]), atoi(params[5])) + sSym = params[6] + rSym = params[7] + bColor = params[8] + fColor = params[9] + try: + fontSize = atoi(params[10]) + fontFam = atoi(params[11]) + fontStyle = atoi(params[12]) + fontWeight = atoi(params[13]) + fontULine = atoi(params[14]) + fontFace = params[15] + except: + print "Font Error!!!" + if (type == MVSLIDERTYPE or \ + type == MHSLIDERTYPE or \ + type == MVGAUGETYPE or \ + type == MHGAUGETYPE): + min = atoi(params[16]) + max = atoi(params[17]) + dir = atoi(params[18]) + label = [label, min, max, dir] + if (type == MGRAPHTYPE): + min = atof(params[16]) + max = atof(params[17]) + dir = eval(params[18]) + label = [label, min, max, dir] + control = self.addControl(type, label, pos, sSym, rSym) + control.setSize(size) + control.SetBackgroundColour(bColor) + control.SetForegroundColour(fColor) + font = wxFont(fontSize, fontFam, fontStyle, fontWeight, + fontULine, fontFace, wxFONTENCODING_SYSTEM) + control.SetFont(font) + control.setEditMode(self.editMode) + # +1 to include ENDCONTROLMARKER + del list[0:(list.index(ENDCONTROLMARKER) + 1)] + newList.append(control) + return newList + def connect(self): + if (not self.locked): + self.mainFrame.fileMenu.Enable(ID_DISCONNECT, True) + if (not self.cTimer.IsRunning()): + self.cTimer.timeCount = 0 + self.cTimer.Start(CONNECTINTERVAL) + def disconnect(self): + if (self.sTimer.IsRunning()): + self.sTimer.Stop() + try: + self.connection.send(CLOSECOMMAND + SYMMSGSEP + \ + "0" + PAIRSEPCHAR) + except: + pass + self.connection.close() + self.connection = nullConnection() + for control in self.controlList: + control.connection = self.connection + self.cTimer.Stop() + self.pTimer.Stop() + self.pingCount = 0 + if (not self.locked): + self.mainFrame.fileMenu.Enable(ID_CONNECT, True) + self.mainFrame.fileMenu.Enable(ID_DISCONNECT, False) + self.mainFrame.connectIcon.SetBitmap(self.connectImageX) + self.connected = False + def saveToDisk(self, filename): + try: + if (lower(filename[len(filename) - 4:len(filename)]) != ".gpd"): + filename = filename + ".gpd" + file = open(filename, 'w', -1) + self.filepath = getDirectory(filename) + self.filepath = makeAbsolutePath(self.path, self.filepath) + if (self.filepath == ""): + self.filepath = self.path + file.write(repr(self.mainFrame.GetSize()[0]) + "\n") + file.write(repr(self.mainFrame.GetSize()[1]) + "\n") + file.write("#" + colorTuple2HexString((self.mainFrame.mainPanel.\ + GetBackgroundColour().Red(), + self.mainFrame.mainPanel.\ + GetBackgroundColour().Green(), + self.mainFrame.mainPanel.\ + GetBackgroundColour().Blue())) + "\n") + file.write(self.host + "\n") + file.write(repr(self.port) + FILETOKENSEP + + self.joyDevice1 + FILETOKENSEP + + self.joyDevice2 + FILETOKENSEP + + repr(self.pollTime) + FILETOKENSEP + + repr(self.joyPollTime) + FILETOKENSEP + + repr(self.joystickEnabled) + FILETOKENSEP + + repr(self.sendKeys) + FILETOKENSEP + + self.frameTitle + FILETOKENSEP + + repr(self.alwaysOnTop) + FILETOKENSEP + + repr(self.showGrid) + FILETOKENSEP + + repr(self.snapToGrid) + FILETOKENSEP + + repr(self.midiDevice1) + FILETOKENSEP + + repr(self.midiDevice2) + FILETOKENSEP + + repr(self.midiPollTime) + FILETOKENSEP + + repr(self.midiEnabled) + "\n") + self.writeControls(self.controlList, file) + file.close() + self.edited = False + except Exception: + strerror = str(sys.exc_info()[1]) + dlg = wxMessageDialog(self.mainFrame, "Unable to save to " + \ + filename + ":\n\n" + strerror, + "File Error", wxOK) + dlg.ShowModal() + dlg.Destroy() + def openFromDisk(self, filename): + try: + file = open(filename, 'r', -1) + try: + self.filepath = getDirectory(filename) + self.filepath = makeAbsolutePath(self.path, self.filepath) + fullFileList = file.readlines() + for control in self.controlList: + control.mDestroy() + self.controlList = [] + self.selectedControlList = [] + self.resetControlIndecies() + # remove line endings (need Perl's chomp()) + for i in range(0, len(fullFileList)): + fullFileList[i] = replace(fullFileList[i], "\n", "") + frameSize = (atoi(fullFileList[0]), atoi(fullFileList[1])) + panelColor = (fullFileList[2]) + panelHost = (fullFileList[3]) + otherArgs = split(fullFileList[4], FILETOKENSEP) + if (len(otherArgs) > 0): + panelPort = otherArgs[0] + if (len(otherArgs) > 1): + jDev1 = otherArgs[1] + else: + jDev1 = DEFJOYDEVICE1 + if (len(otherArgs) > 2): + jDev2 = otherArgs[2] + else: + jDev2 = DEFJOYDEVICE2 + if (len(otherArgs) > 3): + sockPollTime = atoi(otherArgs[3]) + else: + sockPollTime = DEFSOCKETTIMERTIME + if (len(otherArgs) > 4): + joyPollTime = atoi(otherArgs[4]) + else: + joyPollTime = DEFJOYPOLLTIME + if (len(otherArgs) > 5 and self.joystickAvailable): + self.joystickEnabled = atoi(otherArgs[5]) + if (self.joystickEnabled): + self.startJoystick() + else: + self.stopJoystick() + if (not self.locked): + self.mainFrame.optionsMenu.Check(ID_ENABLEJOY, + self.joystickEnabled) + if (len(otherArgs) > 6): + self.sendKeys = atoi(otherArgs[6]) + if (not self.locked): + self.mainFrame.optionsMenu.Check(ID_ENABLEKEY, + self.sendKeys) + if (len(otherArgs) > 7): + self.setFrameTitle(otherArgs[7]) + if (len(otherArgs) > 8): + self.alwaysOnTop = atoi(otherArgs[8]) + if (len(otherArgs) > 9): + self.showGrid = atoi(otherArgs[9]) + if (len(otherArgs) > 10): + self.snapToGrid = atoi(otherArgs[10]) + if (len(otherArgs) > 11): + self.midiDevice1 = atoi(otherArgs[11]) + if (len(otherArgs) > 12): + self.midiDevice2 = atoi(otherArgs[12]) + if (len(otherArgs) > 13): + self.midiPollTime = atoi(otherArgs[13]) + if (len(otherArgs) > 14 and self.midiAvailable): + self.midiEnabled = atoi(otherArgs[14]) + if (self.midiEnabled): + self.startMidi() + else: + self.stopMidi() + if (not self.locked): + self.mainFrame.optionsMenu.Check(ID_ENABLEMIDI, + self.midiEnabled) + + self.mainFrame.SetSize(frameSize) + self.mainFrame.mainPanel.SetBackgroundColour(panelColor) + self.host = panelHost + self.port = atoi(panelPort) + self.joyDevice1 = jDev1 + self.joyDevice2 = jDev2 + self.pollTime = sockPollTime + self.joyPollTime = joyPollTime + del fullFileList[0:5] + self.readControls(fullFileList) + self.edited = False + self.recreateFrame() + self.mainFrame.mainPanel.Refresh() + except Exception: + strerror = "File is invalid" + #FIXME + strerror = str(sys.exc_info()[1]) + dlg = wxMessageDialog(self.mainFrame, "Unable to open file " + \ + filename + ":\n\n" + strerror, + "File Error", wxOK) + dlg.ShowModal() + dlg.Destroy() + except Exception: + strerror = str(sys.exc_info()[1]) + dlg = wxMessageDialog(self.mainFrame, "Unable to open file " + \ + filename + ":\n\n" + strerror, + "File Error", wxOK) + dlg.ShowModal() + dlg.Destroy() + self.mainFrame.positionIcons() + self.setEditMode(False) + def resetControlIndecies(self): + self.buttonIndex = 0 + self.toggleIndex = 0 + self.sliderIndex = 0 + self.textIndex = 0 + self.rectIndex = 0 + self.gaugeIndex = 0 + self.checkBoxIndex = 0 + self.textBoxIndex = 0 + self.spinButtonIndex = 0 + self.mouseAreaIndex = 0 + self.radioButtonIndex = 0 + self.imageIndex = 0 + self.graphIndex = 0 + def startJoystick(self): + self.joystickEnabled = True + self.joyID1 = joystick.openDevice(self.joyDevice1) + self.joyID2 = joystick.openDevice(self.joyDevice2) + if ((self.joyID1 > -1) or (self.joyID2 > -1)): + self.joyTimer.Start(self.joyPollTime) + if (self.joyID1 == -1): + self.jsOn1 = False + if (not self.locked): + self.mainFrame.jsIcon1.SetBitmap(self.jsImageX) + else: + self.jsOn1 = True + if (not self.locked): + self.mainFrame.jsIcon1.SetBitmap(self.jsImage) + if (self.joyID2 == -1): + self.jsOn2 = False + if (not self.locked): + self.mainFrame.jsIcon2.SetBitmap(self.jsImageX) + else: + self.jsOn2 = True + if (not self.locked): + self.mainFrame.jsIcon2.SetBitmap(self.jsImage) + if (not self.locked): + self.mainFrame.positionIcons() + self.mainFrame.jsIcon1.Show(not self.locked) + self.mainFrame.jsIcon1.Refresh() + self.mainFrame.jsIcon2.Show(not self.locked) + self.mainFrame.jsIcon2.Refresh() + def stopJoystick(self): + self.joyTimer.Stop() + joystick.closeDevice(self.joyID1) + joystick.closeDevice(self.joyID2) + self.joystickEnabled = False + self.jsOn1 = False + self.jsOn2 = False + if (not self.locked): + self.mainFrame.jsIconFlasher1.Stop() + self.mainFrame.jsIconFlasher2.Stop() + self.mainFrame.positionIcons() + self.mainFrame.jsIcon1.Show(False) + self.mainFrame.jsIcon2.Show(False) + def showJoystickActive(self, jsNum): + if (self.joystickEnabled and not self.locked): + if (jsNum == 1): + self.mainFrame.jsIconFlasher1.Start(250) + else: + self.mainFrame.jsIconFlasher2.Start(250) + def startMidi(self): + self.midiEnabled = True + self.midiID1 = midi.openDevice(self.midiDevice1) + self.midiID2 = midi.openDevice(self.midiDevice2) + if ((self.midiID1 > -1) or (self.midiID2 > -1)): + self.midiTimer.Start(self.midiPollTime) + if (self.midiID1 == -1): + self.midiOn1 = False + if (not self.locked): + self.mainFrame.midiIcon1.SetBitmap(self.midiImageX) + else: + self.midiOn1 = True + if (not self.locked): + self.mainFrame.midiIcon1.SetBitmap(self.midiImage) + if (self.midiID2 == -1): + self.midiOn2 = False + if (not self.locked): + self.mainFrame.midiIcon2.SetBitmap(self.midiImageX) + else: + self.midiOn2 = True + if (not self.locked): + self.mainFrame.midiIcon2.SetBitmap(self.midiImage) + if (not self.locked): + self.mainFrame.positionIcons() + self.mainFrame.midiIcon1.Show(not self.locked) + self.mainFrame.midiIcon1.Refresh() + self.mainFrame.midiIcon2.Show(not self.locked) + self.mainFrame.midiIcon2.Refresh() + def stopMidi(self): + self.midiTimer.Stop() + midi.closeDevice(self.midiID1) + midi.closeDevice(self.midiID2) + self.midiEnabled = False + self.midiOn1 = False + self.midiOn2 = False + if (not self.locked): + self.mainFrame.midiIconFlasher1.Stop() + self.mainFrame.midiIconFlasher2.Stop() + self.mainFrame.positionIcons() + self.mainFrame.midiIcon1.Show(False) + self.mainFrame.midiIcon2.Show(False) + def showMidiActive(self, midiNum): + if (self.midiEnabled and not self.locked): + if (midiNum == 1): + self.mainFrame.midiIconFlasher1.Start(250) + else: + self.mainFrame.midiIconFlasher2.Start(250) + def sendCharDown(self, charCode): + self.sendChar(charCode, 1) + def sendCharUp(self, charCode): + self.sendChar(charCode, 0) + def sendChar(self, charCode, downOrUp): + if (self.sendKeys): + self.connection.send("keystroke" + + SYMMSGSEP + + repr(charCode) + + " " + + repr(downOrUp) + + PAIRSEPCHAR) + def lock(self): + if (not self.locked): + if (self.editMode): + self.setEditMode(False) + self.locked = True + self.recreateFrame() + def unlock(self): + if (self.locked): + self.locked = False + self.recreateFrame() + def setEditMode(self, value): + self.editMode = value + self.resizable = value + self.mainFrame.SetCursor(wxHOURGLASS_CURSOR) + self.mainFrame.mainPanel.SetCursor(wxHOURGLASS_CURSOR) + try: + wxYield() + except: + pass + self.recreateFrame() + if (value): + EVT_PAINT(self.mainFrame.mainPanel, self.ePaint) + EVT_LEFT_DOWN(self.mainFrame.mainPanel, self.eLeftDown) + EVT_LEFT_UP(self.mainFrame.mainPanel, self.eLeftUp) + EVT_RIGHT_DOWN(self.mainFrame.mainPanel, self.eRightPopUp) + for control in self.controlList: + control.setEditMode(True) + self.editMode = True + if (not self.locked): + self.mainFrame.editMenu.Enable(ID_ADD, True) + self.mainFrame.editMenu.Enable(ID_EDIT, True) + self.mainFrame.editMenu.Enable(ID_DELETE, True) + self.mainFrame.editMenu.Enable(ID_SELECTALL, True) + self.mainFrame.editMenu.Enable(ID_DUPLICATE, True) + self.mainFrame.editMenu.Enable(ID_ALIGNVERT, True) + self.mainFrame.editMenu.Enable(ID_ALIGNHORZ, True) + self.mainFrame.setEditModeText("Edit Mode") + self.mainFrame.positionIcons() + self.selectedControlList = [] + self.edited = True + if (self.showGrid): + self.mainFrame.mainPanel.Refresh() + else: + self.mainFrame.mainPanel.Disconnect(-1, wxEVT_PAINT) + self.mainFrame.mainPanel.Disconnect(-1, wxEVT_LEFT_DOWN) + self.mainFrame.mainPanel.Disconnect(-1, wxEVT_LEFT_UP) + self.mainFrame.mainPanel.Disconnect(-1, wxEVT_RIGHT_DOWN) + for control in self.controlList: + control.setEditMode(False) + self.editMode = False + if (not self.locked): + self.mainFrame.editMenu.Enable(ID_ADD, False) + self.mainFrame.editMenu.Enable(ID_EDIT, False) + self.mainFrame.editMenu.Enable(ID_DELETE, False) + self.mainFrame.editMenu.Enable(ID_SELECTALL, False) + self.mainFrame.editMenu.Enable(ID_DUPLICATE, False) + self.mainFrame.editMenu.Enable(ID_ALIGNVERT, False) + self.mainFrame.editMenu.Enable(ID_ALIGNHORZ, False) + self.mainFrame.setEditModeText("Performance Mode") + self.mainFrame.positionIcons() + for control in self.controlList: + control.Refresh() + self.mainFrame.SetCursor(wxSTANDARD_CURSOR) + self.mainFrame.mainPanel.SetCursor(wxSTANDARD_CURSOR) + self.mainFrame.mainPanel.SetFocus() + def recreateFrame(self): + position = self.mainFrame.GetPosition() + newWindow = gripdFrame(self, + -1, + self.frameTitle, + position, + self.resizable, + self.locked, + self.alwaysOnTop) + shown = self.mainFrame.IsShown() + self.copyFrame(newWindow) + if (shown): + self.mainFrame.Show(True) + try: + wxYield() + except: + pass + self.setFrameTitle(self.frameTitle) + def copyFrame(self, newWindow): + newWindow.SetSize(self.mainFrame.GetSize()) + if (not self.locked): + newWindow.editMenu.Check(ID_EDITMODE, + self.editMode) + newWindow.optionsMenu.Check(ID_ENABLEJOY, + self.joystickEnabled) + newWindow.optionsMenu.Check(ID_ENABLEMIDI, + self.midiEnabled) + newWindow.optionsMenu.Check(ID_ENABLEKEY, + self.sendKeys) + newWindow.positionIcons() + newWindow.jsIcon1.Show(self.joystickEnabled) + newWindow.jsIcon2.Show(self.joystickEnabled) + newWindow.midiIcon1.Show(self.midiEnabled) + newWindow.midiIcon2.Show(self.midiEnabled) + if (self.jsOn1 and not self.locked): + newWindow.jsIcon1.SetBitmap(self.jsImage) + elif (not self.locked): + newWindow.jsIcon1.SetBitmap(self.jsImageX) + if (self.jsOn2 and not self.locked): + newWindow.jsIcon2.SetBitmap(self.jsImage) + elif (not self.locked): + newWindow.jsIcon2.SetBitmap(self.jsImageX) + if (self.midiOn1 and not self.locked): + newWindow.midiIcon1.SetBitmap(self.midiImage) + elif (not self.locked): + newWindow.midiIcon1.SetBitmap(self.midiImageX) + if (self.midiOn2 and not self.locked): + newWindow.midiIcon2.SetBitmap(self.midiImage) + elif (not self.locked): + newWindow.midiIcon2.SetBitmap(self.midiImageX) + newWindow.mainPanel.SetBackgroundColour(\ + self.mainFrame.mainPanel.GetBackgroundColour()) + self.mainFrame.Destroy() + if (self.connected and not self.locked): + newWindow.fileMenu.Enable(ID_CONNECT, False) + newWindow.fileMenu.Enable(ID_DISCONNECT, True) + newWindow.connectIcon.SetBitmap(self.connectImage) + elif (not self.locked): + newWindow.fileMenu.Enable(ID_CONNECT, True) + newWindow.fileMenu.Enable(ID_DISCONNECT, False) + newWindow.connectIcon.SetBitmap(self.connectImageX) + self.SetTopWindow(newWindow) + self.mainFrame = newWindow + EVT_KEY_UP(self.mainFrame.mainPanel, self.eKeyUp) + EVT_KEY_DOWN(self.mainFrame.mainPanel, self.eKeyDown) + EVT_CHAR(self.mainFrame.mainPanel, self.eChar) + if (not os.name == "posix"): + EVT_CHAR_HOOK(self.mainFrame, self.eChar) + EVT_CLOSE(self.mainFrame, self.eClose) + EVT_SIZE(self.mainFrame, self.eSize) + list = [] + container = duplicationContainer() + for control in self.controlList: + list.append(control) + self.controlList = [] + self.writeControls(list, container) + container.chomp() + self.readControls(container.getList()) + def setFrameTitle(self, value): + self.frameTitle = value + if (self.editMode): + self.mainFrame.SetTitle(value + " [ Edit ]") + else: + self.mainFrame.SetTitle(value) + def pingTimeout(self): + if (self.openAuto): + debugLog("timeout") + self.disconnect() + self.close() + else: + self.disconnect() + def getNearestGridPoint(self, point): + x = self.gridSpace * round((float(point[0]) / self.gridSpace)) + y = self.gridSpace * round((float(point[1]) / self.gridSpace)) + gridPoint = (int(x), int(y)) + return gridPoint + def close(self): + self.openAuto = False + if ((self.edited) and (len(self.controlList) > 0)): + self.mainFrame.Show(True) + dlg = wxMessageDialog(self.mainFrame, + "Current GUI not saved. Close anyway?", + "GUI Not Saved", wxOK | wxCANCEL) + if (dlg.ShowModal() == wxID_OK): + dlg.Destroy() + self.mainFrame.Destroy() + try: + self.disconnect() + except: + pass + else: + return + else: + self.mainFrame.Show(True) + self.mainFrame.Destroy() + try: + self.disconnect() + except: + pass + if (self.joystickEnabled): + self.stopJoystick() + if (self.midiEnabled): + self.stopMidi() + self.ExitMainLoop() + +## Events ## + + def eOpenConnection(self, event): + cString = "Connect to " + self.host + ":" + repr(self.port) + "\n " + dlg = wxMessageDialog(self.mainFrame.mainPanel, cString, "Connect", + wxOK | wxCANCEL) + if (dlg.ShowModal() == wxID_OK): + self.connect() + dlg.Destroy() + def eCloseConnection(self, event): + self.disconnect() + def eToggleJoystick(self, event): + if (not self.locked): + self.joystickEnabled = self.mainFrame.optionsMenu.\ + IsChecked(ID_ENABLEJOY) + if (self.joystickEnabled): + self.startJoystick() + else: + self.stopJoystick() + def eToggleMidi(self, event): + if (not self.locked): + self.midiEnabled = self.mainFrame.optionsMenu.\ + IsChecked(ID_ENABLEMIDI) + if (self.midiEnabled): + self.startMidi() + else: + self.stopMidi() + def eToggleKeySend(self, event): + if (not self.locked): + self.sendKeys = self.mainFrame.optionsMenu.IsChecked(ID_ENABLEKEY) + def eToggleAlwaysOnTop(self, event): + if (not self.locked and os.name != "posix"): + self.alwaysOnTop = self.mainFrame.optionsMenu.\ + IsChecked(ID_ALWAYSONTOP) + self.recreateFrame() + def eToggleShowGrid(self, event): + self.showGrid = self.mainFrame.optionsMenu.IsChecked(ID_SHOWGRID) + if (not self.showGrid): + self.snapToGrid = False + if (not self.locked): + self.mainFrame.optionsMenu.Check(ID_SNAPTOGRID, False) + else: + if (self.editMode): + self.mainFrame.mainPanel.Refresh() + self.mainFrame.mainPanel.Refresh() + def eToggleSnapToGrid(self, event): + self.snapToGrid = self.mainFrame.optionsMenu.IsChecked(ID_SNAPTOGRID) + if (self.snapToGrid): + self.showGrid = True + if (not self.locked): + self.mainFrame.optionsMenu.Check(ID_SHOWGRID, True) + if (self.editMode): + self.mainFrame.mainPanel.Refresh() + def eRightPopUp(self, event): + if ((not self.locked) and (not self.selecting)): + self.mainFrame.PopupMenuXY(self.mainFrame.editMenu, + event.GetX(), + event.GetY()) + def eLeftDown(self, event): + # Editing stuff (mostly for selectRect) + if (self.editMode): + EVT_MOTION(self.mainFrame.mainPanel, self.eMotion) + self.mouseDownPos = event.GetPosition() + self.mainFrame.mainPanel.CaptureMouse() + self.leftDownOnPanel = True + if (not event.m_controlDown): + self.deselectOthers(-1) + def eLeftUp(self, event): + if (self.editMode): + if (self.leftDownOnPanel): + self.mainFrame.mainPanel.ReleaseMouse() + self.mainFrame.mainPanel.Disconnect(-1, wxEVT_MOTION) + if (self.selecting): + self.selecting = False + for control in self.controlList: + if (selectIntersect(control.GetRect(), + self.mainFrame.selectRect)): + control.select() + elif ((not event.m_controlDown) and control.isSelected()): + control.deselect() + self.mainFrame.mainPanel.Refresh() + self.leftDownOnPanel = False + def eMotion(self, event): + if (event.LeftIsDown() and self.editMode and self.leftDownOnPanel): + self.selecting = True + width = abs(event.GetPosition()[0] - self.mouseDownPos[0]) + height = abs(event.GetPosition()[1] - self.mouseDownPos[1]) + leftBound = min(self.mouseDownPos[0], event.GetPosition()[0]) + topBound = min(self.mouseDownPos[1], event.GetPosition()[1]) + clearRegion = wxRegion(self.mainFrame.selectRect[0], + self.mainFrame.selectRect[1], + self.mainFrame.selectRect[2], + self.mainFrame.selectRect[3]) + self.mainFrame.selectRect = [leftBound, topBound, + width, height] + clearRegion.Union(leftBound, topBound, width, height) + self.mainFrame.mainPanel.Refresh(False, clearRegion.GetBox()) + def ePaint(self, event): + event.Skip() + myDC = wxPaintDC(self.mainFrame.mainPanel) + myDC.BeginDrawing() + if (self.editMode): + if (self.showGrid): + self.mainFrame.drawGrid(myDC) + else: + self.mainFrame.drawCleanBackground(myDC) + if (self.selecting): + self.mainFrame.drawSelectRect(myDC) + myDC.EndDrawing() + def eAddButton(self, event): + self.createControl(MBUTTONTYPE, self.buttonIndex, "button") + def eAddToggle(self, event): + self.createControl(MTOGGLETYPE, self.toggleIndex, "toggle") + def eAddVSlider(self, event): + self.createControl(MVSLIDERTYPE, self.sliderIndex, "slider") + def eAddHSlider(self, event): + self.createControl(MHSLIDERTYPE, self.sliderIndex, "slider") + def eAddRect(self, event): + self.createControl(MRECTTYPE, self.rectIndex, "rectangle") + def eAddText(self, event): + self.createControl(MTEXTTYPE, self.textIndex, "text") + def eAddVGauge(self, event): + self.createControl(MVGAUGETYPE, self.gaugeIndex, "gauge") + def eAddHGauge(self, event): + self.createControl(MHGAUGETYPE, self.gaugeIndex, "gauge") + def eAddCheckBox(self, event): + self.createControl(MCHECKBOXTYPE, self.checkBoxIndex, "checkbox") + def eAddRadioButtons(self, event): + if (self.editMode and not self.dragging): + txtDialog = wxTextEntryDialog(self.mainFrame.mainPanel, + "Number of radio buttons to add:", + "Create Radio Buttons", "2") + if (txtDialog.ShowModal() == wxID_OK): + numRadButs = atoi(txtDialog.GetValue()) + txtDialog.Destroy() + if (numRadButs > 1): + indexStr = "radiobutton" + repr(self.radioButtonIndex) + pos = self.mainFrame.mainPanel.ScreenToClient( \ + wxGetMousePosition()) + controlN = self.addControl(MRADIONEWTYPE, + indexStr, + pos, + "s" + indexStr, + "r" + indexStr) + coords = pos + for i in range(1, numRadButs): + indexStr = "radiobutton" + repr(self.radioButtonIndex) + coords = [coords[0], coords[1] + 25] + maxPos = self.mainFrame.mainPanel.GetSize()[1] - 10 + minPos = 0 + if (coords[1] > maxPos): + coords[0] = pos[0] + 40 + coords[1] = pos[1] + control = self.addControl(MRADIOBUTTONTYPE, + indexStr, + coords, + "s" + indexStr, + "r" + indexStr) + control.select() + controlN.select() + try: + wxYield() + except: + pass + controlN.grab() + def eAddTextBox(self, event): + self.createControl(MTEXTBOXTYPE, self.textBoxIndex, "textbox") + def eAddSpinButton(self, event): + self.createControl(MSPINBUTTONTYPE, self.spinButtonIndex, "spinbutton") + def eAddMouseArea(self, event): + self.createControl(MMOUSEAREATYPE, self.mouseAreaIndex, "mousearea") + def eAddImage(self, event): + if (self.editMode and not self.dragging): + dlg = wxFileDialog(self.mainFrame, "Open file", self.filepath, + "", "*.*", wxOPEN) + if (dlg.ShowModal() == wxID_OK): + filepath = dlg.GetPath() + self.createControl(MIMAGETYPE, + self.imageIndex, + "image", + filepath) + dlg.Destroy() + def eAddGraph(self, event): + self.createControl(MGRAPHTYPE, self.graphIndex, "graph") + def eEditMode(self, event): + if (not self.locked): + newEditMode = self.mainFrame.editMenu.IsChecked(ID_EDITMODE) + self.setEditMode(newEditMode) + def eEditControl(self, event): + self.edited = True + if (len(self.selectedControlList) > 0): + self.selectedControlList[0].eEdit(event) + # extra array needed because we're removing items from the array + # we are cycling through (selectedControlList) + def eDeleteControl(self, event): + deleteList = [] + for control in self.selectedControlList: + deleteList.append(control) + for control in deleteList: + self.controlList.remove(control) + self.selectedControlList.remove(control) + control.mDestroy() + def eSelectAll(self, event): + for control in self.controlList: + control.select() + def eDuplicate(self, event): + list = [] + container = duplicationContainer() + # Not using selectedControlList since we are removing from it + # as we cycle through the list + for control in self.controlList: + if (control.isSelected()): + list.append(control) + control.deselect() + self.writeControls(list, container) + container.chomp() + for control in self.readControls(container.getList()): + control.select() + control.move(DUPPOSOFFSET) + def eAlignVertical(self, event): + self.alignControls(0) + def eAlignHorizontal(self, event): + self.alignControls(1) + def eRefresh(self, event): + for control in self.controlList: + control.Refresh() + if (control.isSelected()): + control.relocateTags() + self.mainFrame.mainPanel.Refresh(True) + def eNew(self, event): + flag = 0; + if ((self.edited) and (len(self.controlList) > 0)): + flag = 1 + dlg = wxMessageDialog(self.mainFrame, + "Current GUI not saved. Clear anyway?", + "GUI Not Saved", wxOK | wxCANCEL) + if (dlg.ShowModal() == wxID_OK): + flag = 0 + if (not flag): + for control in self.controlList: + control.mDestroy() + self.controlList = [] + self.selectedControlList = [] + self.resetControlIndecies() + self.mainFrame.mainPanel.SetBackgroundColour(\ + self.mainFrame.defBgColor) + self.mainFrame.mainPanel.Refresh() + self.filepath = "" + def eOpen(self, event): + if ((self.edited) and (len(self.controlList) > 0)): + dlg2 = wxMessageDialog(self.mainFrame, + "Current GUI not saved. Open anyway?", + "GUI Not Saved", wxOK | wxCANCEL) + if (dlg2.ShowModal() == wxID_OK): + dlg = wxFileDialog(self.mainFrame, + "Open file", self.filepath, "", "*.gpd", + wxOPEN) + if (dlg.ShowModal() == wxID_OK): + self.openFromDisk(dlg.GetPath()) + # FIXME + # dlg.Destroy() + # FIXME + # dlg2.Destroy() + else: + dlg = wxFileDialog(self.mainFrame, + "Open file", self.filepath, "", "*.gpd", + wxOPEN) + if (dlg.ShowModal() == wxID_OK): + self.openFromDisk(dlg.GetPath()) + # FIXME + # dlg.Destroy() + self.mainFrame.mainPanel.Refresh() + def eSave(self, event): + dlg = wxFileDialog(self.mainFrame, "Save file", self.filepath, + "", "*.gpd", wxSAVE) + if (dlg.ShowModal() == wxID_OK): + filename = dlg.GetPath() + try: + file = open(filename, 'r', -1) + file.close() + dlg2 = wxMessageDialog(self.mainFrame, "File " + filename \ + + " already exists. Overwrite?", + "File Exists", wxOK | wxCANCEL) + if (dlg2.ShowModal() == wxID_OK): + self.saveToDisk(filename) + dlg2.Destroy() + except: + self.saveToDisk(filename) + dlg.Destroy() + def eSetOptions(self, event): + dlg = optionsDialog(self) + dlg.ShowModal() + self.host = dlg.addrBox.GetValue() + try: + self.port = atoi(dlg.portBox.GetValue()) + except: + errDlg = wxMessageDialog(self.mainFrame, + "Invalid Port", + "Options Error", + wxOK) + errDlg.ShowModal() + errDlg.Destroy() + try: + self.pollTime = atoi(dlg.pollBox.GetValue()) + except: + errDlg = wxMessageDialog(self.mainFrame, + "Invalid Socket Poll Time", + "Options Error", + wxOK) + errDlg.ShowModal() + errDlg.Destroy() + self.joyDevice1 = dlg.joyDevBox1.GetValue() + self.joyDevice2 = dlg.joyDevBox2.GetValue() + try: + self.joyPollTime = atoi(dlg.joyPollBox.GetValue()) + except: + errDlg = wxMessageDialog(self.mainFrame, + "Invalid Joystick Poll Time", + "Options Error", + wxOK) + errDlg.ShowModal() + errDlg.Destroy() + try: + self.midiDevice1 = atoi(dlg.midiDevBox1.GetValue()) + except: + errDlg = wxMessageDialog(self.mainFrame, + "Invalid MIDI Device 0\nShould be an integer.", + "Options Error", + wxOK) + errDlg.ShowModal() + errDlg.Destroy() + try: + self.midiDevice2 = atoi(dlg.midiDevBox2.GetValue()) + except: + errDlg = wxMessageDialog(self.mainFrame, + "Invalid MIDI Device 1\nShould be an integer.", + "Options Error", + wxOK) + errDlg.ShowModal() + errDlg.Destroy() + try: + self.midiPollTime = atoi(dlg.midiPollBox.GetValue()) + except: + errDlg = wxMessageDialog(self.mainFrame, + "Invalid MIDI Poll Time", + "Options Error", + wxOK) + errDlg.ShowModal() + errDlg.Destroy() + self.setFrameTitle(dlg.titleBox.GetValue()) + if (self.sTimer.IsRunning): + self.sTimer.Stop() + self.sTimer.Start(self.pollTime) + if (not self.locked): + if (self.mainFrame.optionsMenu.IsChecked(ID_ENABLEJOY)): + self.stopJoystick() + self.startJoystick() + if (self.mainFrame.optionsMenu.IsChecked(ID_ENABLEMIDI)): + self.stopMidi() + self.startMidi() + dlg.Destroy() + self.mainFrame.Refresh(True) + self.mainFrame.mainPanel.Refresh(True) + for control in self.controlList: + control.Refresh() + def eAbout(self, event): + aboutString = "GrIPD v" + VERSION + ": " + aboutString = aboutString \ + + "Graphical Interface for Pure Data\n\n" + aboutString = aboutString \ + + "(C) Copyright 2003 Joseph A. Sarlo\nGNU " + aboutString = aboutString \ + + "General Public License\njsarlo@ucsd.edu" + dlg = wxMessageDialog(self.mainFrame, aboutString , "About GrIPD", + wxOK | wxICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + def eQuit(self, event): + self.mainFrame.Close(True) + def eKeyDown(self, event): + # already depressed + try: + self.keysDown.index(event.GetKeyCode()) + # first time + except: + self.keysDown.append(event.GetKeyCode()) + if (not self.editMode): + self.sendCharDown(event.GetKeyCode()) + event.Skip() + def eKeyUp(self, event): + try: + self.keysDown.remove(event.GetKeyCode()) + self.sendCharUp(event.GetKeyCode()) + except: + pass + event.Skip() + def eChar(self, event): + if (self.editMode and not self.dragging): + if (event.m_controlDown): + deltaPos = LARGECHARMOVE + else: + deltaPos = SMALLCHARMOVE + if (event.GetKeyCode() == WXK_LEFT): + self.moveKey((-deltaPos, 0)) + return + if (event.GetKeyCode() == WXK_RIGHT): + self.moveKey((deltaPos, 0)) + return + if (event.GetKeyCode() == WXK_UP): + self.moveKey((0, -deltaPos)) + return + if (event.GetKeyCode() == WXK_DOWN): + self.moveKey((0, deltaPos)) + return + if (event.GetKeyCode() == WXK_TAB): + self.traverseFocus(event.m_controlDown) + return + if (not self.editMode or (self.editMode and not self.dragging)): + # Allow accelerators to be called + event.Skip() + def eRepaintControlTags(self, event): + event.getControl().refreshTags() + def eClose(self, event): + if (self.openAuto and self.connected): + self.mainFrame.Show(False) + try: + self.connection.send(HIDECOMMAND + SYMMSGSEP + \ + "0" + PAIRSEPCHAR) + except: + self.close() + else: + self.close() + def eSize(self, event): + self.mainFrame.positionIcons() + event.Skip() + +# Frame class +class gripdFrame(wxFrame): +# Setup + def __init__(self, parent, ID, title, position, + resizable, locked, alwaysOnTop): + self.mParent = parent + self.resizable = resizable + self.alwaysOnTop = alwaysOnTop + self.locked = locked + if (self.resizable): + style = wxDEFAULT_FRAME_STYLE + else: + style = wxDEFAULT_FRAME_STYLE & (~wxRESIZE_BORDER) & \ + (~wxMAXIMIZE_BOX) + if (self.alwaysOnTop): + style = style | wxSTAY_ON_TOP + if (position == (-1, -1)): + position = wxDefaultPosition + wxFrame.__init__(self, NULL, ID, title, position, + DEFMAINFRAMESIZE, + style) + if (not os.name == "posix"): + self.SetIcon(self.mParent.icon) + if (not self.locked): + # Menu accelerator stuff + aclList = [] + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, + WXK_DELETE, + ID_DELETE)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F1, + ID_BUTTON)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F2, + ID_TOGGLE)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F3, + ID_SPINBUTTON)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F4, + ID_RADIOBUTTON)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F5, + ID_VSLIDER)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F6, + ID_HSLIDER)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F7, + ID_VGAUGE)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F8, + ID_HGAUGE)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F9, + ID_CHECKBOX)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F10, + ID_TEXTBOX)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F11, + ID_MOUSEAREA)) + aclList.append(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F12, + ID_RECT)) + aclList.append(wxAcceleratorEntry(wxACCEL_ALT, ord("1"), + ID_TEXT)) + aclList.append(wxAcceleratorEntry(wxACCEL_ALT, ord("2"), + ID_IMAGE)) + self.SetAcceleratorTable(wxAcceleratorTable(aclList)) + self.menuBar = wxMenuBar() + self.SetMenuBar(self.menuBar) + self.createMenu() + self.CreateStatusBar(3) + self.jsIcon1 = wxStaticBitmap(self.GetStatusBar(), -1, + self.mParent.jsImageX, (0, 0), + wxDefaultSize) + self.jsIcon2 = wxStaticBitmap(self.GetStatusBar(), -1, + self.mParent.jsImageX, (0, 0), + wxDefaultSize) + self.midiIcon1 = wxStaticBitmap(self.GetStatusBar(), -1, + self.mParent.midiImageX, (0, 0), + wxDefaultSize) + self.midiIcon2 = wxStaticBitmap(self.GetStatusBar(), -1, + self.mParent.midiImageX, (0, 0), + wxDefaultSize) + self.connectIcon = wxStaticBitmap(self.GetStatusBar(), + -1, + self.mParent.connectImageX, + (0, 0), + wxDefaultSize) + # timers to flash icons + self.jsIconFlasher1 = iconFlasher(self.jsIcon1, + self.mParent.jsImage, + self.mParent.jsImageA, + 1) + self.jsIconFlasher2 = iconFlasher(self.jsIcon2, + self.mParent.jsImage, + self.mParent.jsImageA, + 1) + self.midiIconFlasher1 = iconFlasher(self.midiIcon1, + self.mParent.midiImage, + self.mParent.midiImageA, + 1) + self.midiIconFlasher2 = iconFlasher(self.midiIcon2, + self.mParent.midiImage, + self.mParent.midiImageA, + 1) + self.editModeText = wxStaticText(self.GetStatusBar(), + -1, + "Performance Mode", + (0, 0), + wxDefaultSize, + wxALIGN_CENTRE | \ + wxST_NO_AUTORESIZE) + self.editModeText.Show(True) + self.jsIcon1.Show(False) + self.jsIcon2.Show(False) + self.midiIcon1.Show(False) + self.midiIcon2.Show(False) + self.connectIcon.Show(True) + # left, top, width, height of selection rect (for drawing) + self.selectRect = [0, 0, 0, 0] + # mainPanel stuff + self.mainPanel = wxPanel(self, -1, wxDefaultPosition, + wxDefaultSize, + wxSTATIC_BORDER) + self.defBgColor = wxColour(self.mainPanel.GetBackgroundColour().Red() \ + - BGCOLORDIF, + self.mainPanel.GetBackgroundColour().Green() \ + - BGCOLORDIF, + self.mainPanel.GetBackgroundColour().Blue() \ + - BGCOLORDIF) + self.mainPanel.SetBackgroundColour(self.defBgColor) + self.mainPanel.Show(True) + if (self.locked): + self.lock() + else: + self.unlock() + def createMenu(self): + self.fileMenu = wxMenu() + self.fileMenu.Append(ID_NEW, "&New\tCtrl-N", "Clear current GUI") + self.fileMenu.Append(ID_OPEN, "&Open\tCtrl-O", "Open a GUI") + self.fileMenu.Append(ID_SAVE, "&Save\tCtrl-S", "Save current GUI") + self.fileMenu.AppendSeparator() + self.fileMenu.Append(ID_CONNECT, "&Connect\tAlt-C", + "Connect to PD") + self.fileMenu.Append(ID_DISCONNECT, "&Disconnect\tAlt-D", + "Disconnect from PD") + self.fileMenu.AppendSeparator() + self.fileMenu.Append(ID_EXIT, "E&xit\tCtrl-Q", "Quit GrIPD") + self.editMenu = wxMenu() + self.editMenu.Append(ID_EDITMODE, "Edit &mode\tCtrl-E", + "Toggle Edit/Performance Modes", True) + self.editMenu.AppendSeparator() + self.addMenu = wxMenu() + self.buttonMenu = wxMenu() + self.buttonMenu.Append(ID_BUTTON, "&Push Button\tF1", + "Add a push button") + self.buttonMenu.Append(ID_TOGGLE, "&Toggle Button\tF2", + "Add a toggle button") + self.buttonMenu.Append(ID_SPINBUTTON, "&Spin Button\tF3", + "Add a spin button") + self.buttonMenu.Append(ID_RADIOBUTTON, "&Radio Buttons\tF4", + "Add radio buttons") + self.addMenu.AppendMenu(ID_BUTTONMENU, "&Button", self.buttonMenu); + self.sliderMenu = wxMenu() + self.sliderMenu.Append(ID_VSLIDER, "&Vertical Slider\tF5", + "Add a vertical slider") + self.sliderMenu.Append(ID_HSLIDER, "&Horizontal Slider\tF6", + "Add a horizontal slider") + self.addMenu.AppendMenu(ID_SLIDERMENU, "&Slider", self.sliderMenu); + self.gaugeMenu = wxMenu() + self.gaugeMenu.Append(ID_VGAUGE, "&Vertical Gauge\tF7", + "Add a vertical gauge") + self.gaugeMenu.Append(ID_HGAUGE, "&Horizontal Gauge\tF8", + "Add a horizontal gauge") + self.addMenu.AppendMenu(ID_GAUGEMENU, "&Gauge", self.gaugeMenu); + self.addMenu.Append(ID_CHECKBOX, "&Checkbox\tF9", + "Add a labeld checkbox") + self.addMenu.Append(ID_TEXTBOX, "Te&xtbox\tF10", + "Add a box for entering text") + self.addMenu.Append(ID_MOUSEAREA, "&Mouse Area\tF11", + "Add a mouse capture area") + self.addMenu.Append(ID_RECT, "&Rectangle\tF12", + "Add a boundary rectangle") + self.addMenu.Append(ID_TEXT, "&Text\tAlt-1", "Add text") + self.addMenu.Append(ID_IMAGE, "&Image\tAlt-2", "Add an image") + self.addMenu.Append(ID_GRAPH, "&Graph\tAlt-3", "Add a graph") + self.editMenu.AppendMenu(ID_ADD, "&Add", self.addMenu) + self.editMenu.Append(ID_EDIT, "&Edit", "Edit selected controls") + self.editMenu.Append(ID_DELETE, "&Delete", "Delete selected controls") + self.editMenu.AppendSeparator() + self.editMenu.Append(ID_SELECTALL, "&Select All\tCtrl-A", + "Select all controls") + self.editMenu.Append(ID_DUPLICATE, "D&uplicate\tCtrl-D", + "Duplicate selected controls") + self.editMenu.AppendSeparator() + self.editMenu.Append(ID_ALIGNVERT, "Align &Vertical\tCtrl-V", + "Vertically align selected controls") + self.editMenu.Append(ID_ALIGNHORZ, "Align &Horizontal\tCtrl-H", + "Horizontally align selected controls") + self.editMenu.AppendSeparator() + self.editMenu.Append(ID_REFRESH, "&Refresh\tCtrl-R", "Refresh screen") + self.optionsMenu = wxMenu() + if (os.name != "posix"): + self.optionsMenu.Append(ID_ALWAYSONTOP, "Always On Top", + "Window will stay above all other windows", + True) + self.optionsMenu.AppendSeparator() + self.optionsMenu.Append(ID_ENABLEMIDI, "Enable &MIDI", + "Enables the use of MIDI input", + True) + self.optionsMenu.Append(ID_ENABLEJOY, "Enable &Joystick(s)", + "Enables the use of a joystick", + True) + self.optionsMenu.Append(ID_ENABLEKEY, "Send &Keystrokes", + "Send all keystrokes to PD 'keystroke' symbol", + True) + self.optionsMenu.AppendSeparator() + self.optionsMenu.Append(ID_SHOWGRID, "Show Grid", + "Show Edit Grid", True) + self.optionsMenu.Append(ID_SNAPTOGRID, "Snap To Grid", + "Snap controls to edit grid", True) + self.optionsMenu.AppendSeparator() + self.optionsMenu.Append(ID_SETOPTS, "&Configure\tCtrl-C", + "Set GUI options") + self.helpMenu = wxMenu() + self.helpMenu.Append(ID_ABOUT, "&About", + "GrIPD: Graphical Interface for Pure Data") + self.menuBar.Append(self.fileMenu, "&File") + self.menuBar.Append(self.editMenu, "&Edit") + self.menuBar.Append(self.optionsMenu, "&Options") + self.menuBar.Append(self.helpMenu, "&Help") + self.fileMenu.Enable(ID_DISCONNECT, False) + self.editMenu.Enable(ID_ADD, False) + self.editMenu.Enable(ID_EDIT, False) + self.editMenu.Enable(ID_DELETE, False) + self.editMenu.Enable(ID_SELECTALL, False) + self.editMenu.Enable(ID_DUPLICATE, False) + self.editMenu.Enable(ID_ALIGNVERT, False) + self.editMenu.Enable(ID_ALIGNHORZ, False) + if (self.mParent.joystickAvailable): + self.optionsMenu.Check(ID_ENABLEJOY, self.mParent.joystickEnabled) + if (self.mParent.midiAvailable): + self.optionsMenu.Check(ID_ENABLEMIDI, self.mParent.midiEnabled) + self.optionsMenu.Check(ID_ENABLEKEY, self.mParent.sendKeys) + if (os.name != "posix"): + self.optionsMenu.Check(ID_ALWAYSONTOP, self.alwaysOnTop) + self.optionsMenu.Check(ID_SHOWGRID, self.mParent.showGrid) + self.optionsMenu.Check(ID_SNAPTOGRID, self.mParent.snapToGrid) + self.optionsMenu.Enable(ID_ENABLEJOY, + self.mParent.joystickAvailable) + self.optionsMenu.Enable(ID_ENABLEMIDI, + self.mParent.midiAvailable) + EVT_MENU(self, ID_NEW, self.mParent.eNew) + EVT_MENU(self, ID_ABOUT, self.mParent.eAbout) + EVT_MENU(self, ID_EXIT, self.mParent.eQuit) + EVT_MENU(self, ID_CONNECT, self.mParent.eOpenConnection) + EVT_MENU(self, ID_DISCONNECT, self.mParent.eCloseConnection) + EVT_MENU(self, ID_OPEN, self.mParent.eOpen) + EVT_MENU(self, ID_SAVE, self.mParent.eSave) + EVT_MENU(self, ID_BUTTON, self.mParent.eAddButton) + EVT_MENU(self, ID_TOGGLE, self.mParent.eAddToggle) + EVT_MENU(self, ID_SPINBUTTON, self.mParent.eAddSpinButton) + EVT_MENU(self, ID_VSLIDER, self.mParent.eAddVSlider) + EVT_MENU(self, ID_HSLIDER, self.mParent.eAddHSlider) + EVT_MENU(self, ID_RECT, self.mParent.eAddRect) + EVT_MENU(self, ID_VGAUGE, self.mParent.eAddVGauge) + EVT_MENU(self, ID_HGAUGE, self.mParent.eAddHGauge) + EVT_MENU(self, ID_CHECKBOX, self.mParent.eAddCheckBox) + EVT_MENU(self, ID_RADIOBUTTON, self.mParent.eAddRadioButtons) + EVT_MENU(self, ID_TEXTBOX, self.mParent.eAddTextBox) + EVT_MENU(self, ID_TEXT, self.mParent.eAddText) + EVT_MENU(self, ID_IMAGE, self.mParent.eAddImage) + EVT_MENU(self, ID_MOUSEAREA, self.mParent.eAddMouseArea) + EVT_MENU(self, ID_GRAPH, self.mParent.eAddGraph) + EVT_MENU(self, ID_EDITMODE, self.mParent.eEditMode) + EVT_MENU(self, ID_EDIT, self.mParent.eEditControl) + EVT_MENU(self, ID_DELETE, self.mParent.eDeleteControl) + EVT_MENU(self, ID_SELECTALL, self.mParent.eSelectAll) + EVT_MENU(self, ID_DUPLICATE, self.mParent.eDuplicate) + EVT_MENU(self, ID_ALIGNVERT, self.mParent.eAlignVertical) + EVT_MENU(self, ID_ALIGNHORZ, self.mParent.eAlignHorizontal) + EVT_MENU(self, ID_REFRESH, self.mParent.eRefresh) + EVT_MENU(self, ID_SETOPTS, self.mParent.eSetOptions) + EVT_MENU(self, ID_ENABLEJOY, self.mParent.eToggleJoystick) + EVT_MENU(self, ID_ENABLEMIDI, self.mParent.eToggleMidi) + EVT_MENU(self, ID_ENABLEKEY, self.mParent.eToggleKeySend) + if (os.name != "posix"): + EVT_MENU(self, ID_ALWAYSONTOP, self.mParent.eToggleAlwaysOnTop) + EVT_MENU(self, ID_SHOWGRID, self.mParent.eToggleShowGrid) + EVT_MENU(self, ID_SNAPTOGRID, self.mParent.eToggleSnapToGrid) + def createLockedMenu(self): + self.fileMenu = wxMenu() + self.fileMenu.Append(ID_EXIT, "E&xit\tCtrl-Q", "Quit GrIPD") + self.helpMenu = wxMenu() + self.helpMenu.Append(ID_ABOUT, "&About", + "GrIPD: Graphical Interface for Pure Data") + self.menuBar.Append(self.fileMenu, "&File") + self.menuBar.Append(self.helpMenu, "&Help") + EVT_MENU(self, ID_ABOUT, self.mParent.eAbout) + EVT_MENU(self, ID_EXIT, self.mParent.eQuit) + def removeMenu(self): + for i in range(0, self.GetMenuBar().GetMenuCount()): + self.GetMenuBar().Remove(0) + def drawCleanBackground(self, myDC, rect = ()): + box = self.mainPanel.GetUpdateRegion().GetBox() + if (rect == ()): + rect = tuple((box[0], + box[1], + box[0] + box[2], + box[1] + box[3])) + myDC.SetPen(wxPen(self.mainPanel.GetBackgroundColour(), + 1, + wxTRANSPARENT)) + myDC.SetBrush(wxBrush(self.mainPanel.GetBackgroundColour(), wxSOLID)) + myDC.DrawRectangle(rect[0], + rect[1], + rect[2], + rect[3]) + def drawGrid(self, myDC, rect = ()): + box = self.mainPanel.GetUpdateRegion().GetBox() + if (rect == ()): + rect = tuple((box[0], + box[1], + box[0] + box[2], + box[1] + box[3])) + color = self.mainPanel.GetBackgroundColour() + newColorTuple = [color.Red() - 50, + color.Green() - 50, + color.Blue() - 50] + if (newColorTuple[0] < 0 or \ + newColorTuple[1] < 0 or \ + newColorTuple[2] < 0): + newColorTuple = [color.Red() + 50, + color.Green() + 50, + color.Blue() + 50] + for i in range(0, 3): + if (newColorTuple[i] > 255 or newColorTuple[i] < 0): + newColorTuple[i] = 0 + myDC.SetPen(wxPen(self.mainPanel.GetBackgroundColour(), + 1, + wxTRANSPARENT)) + myDC.SetBrush(wxBrush(self.mainPanel.GetBackgroundColour(), wxSOLID)) + myDC.DrawRectangle(rect[0], + rect[1], + rect[2], + rect[3]) + myDC.SetPen(wxPen(wxColour(newColorTuple[0], + newColorTuple[1], + newColorTuple[2]), + 1, + wxSOLID)) + myDC.SetBrush(wxBrush("#000000", wxTRANSPARENT)) + for i in range(rect[0], rect[2]): + if (i% self.mParent.gridSpace == 0): + myDC.DrawLine(i, rect[1], i, rect[3]) + for i in range(rect[1], rect[3]): + if (i % self.mParent.gridSpace == 0): + myDC.DrawLine(rect[0], i, rect[2], i) + def drawSelectRect(self, myDC): + myDC.SetPen(wxPen("#000000", 1, wxDOT)) + myDC.SetBrush(wxBrush(self.mainPanel.GetBackgroundColour(), + wxTRANSPARENT)) + myDC.DrawRectangle(self.selectRect[0], self.selectRect[1], + self.selectRect[2], self.selectRect[3]) + def setEditModeText(self, text): + if (not self.locked): + self.editModeText.SetLabel(text) + self.editModeText.SetSize(( \ + self.GetStatusBar().GetFieldRect(1)[2] - 10, + self.editModeText.GetSize()[1])) + self.editModeText.Show(True) + pos = (((self.GetStatusBar().GetFieldRect(1)[2] - \ + self.editModeText.GetSize()[0]) / 2) + \ + self.GetStatusBar().GetFieldRect(1)[0] + 1, + ((self.GetStatusBar().GetFieldRect(1)[3] - \ + self.editModeText.GetSize()[1]) / 2) + \ + self.GetStatusBar().GetFieldRect(1)[1] + \ + -1 * (FUGEFACTOR - 2)) + self.editModeText.Move(pos) + def lock(self): + self.locked = True + def unlock(self): + self.locked = False + def positionIcons(self): + if (not self.locked): + self.setEditModeText(self.editModeText.GetLabel()) + pos = (self.GetStatusBar().GetFieldRect(2)[0] + 3, + self.GetStatusBar().GetFieldRect(2)[3] - \ + self.connectIcon.GetSize()[1] + 1) + self.connectIcon.Move(pos) + self.midiIcon1.Move((self.connectIcon.GetPosition()[0] + \ + self.connectIcon.GetSize()[0] + 5, + pos[1])) + self.midiIcon2.Move((self.midiIcon1.GetPosition()[0] + \ + self.midiIcon1.GetSize()[0] + 3, pos[1])) + if (self.mParent.midiEnabled): + self.jsIcon1.Move((self.midiIcon2.GetPosition()[0] + \ + self.midiIcon2.GetSize()[0] + 5, + pos[1])) + else: + self.jsIcon1.Move((self.connectIcon.GetPosition()[0] + \ + self.connectIcon.GetSize()[0] + 5, + pos[1])) + self.jsIcon2.Move((self.jsIcon1.GetPosition()[0] + \ + self.jsIcon1.GetSize()[0] + 3, pos[1])) + + self.Refresh() + def openpanel(self): + dlg = wxFileDialog(self, "Open file", self.mParent.filepath, + "", "*.*", wxOPEN) + if (dlg.ShowModal() == wxID_OK): + filename = dlg.GetPath() + self.mParent.connection.send('openpanel' \ + + SYMMSGSEP \ + + filename \ + + PAIRSEPCHAR) + + + def savepanel(self): + dlg = wxFileDialog(self, "Save file", self.mParent.filepath, + "", "*.*", wxSAVE) + if (dlg.ShowModal() == wxID_OK): + filename = dlg.GetPath() + self.mParent.connection.send('savepanel' \ + + SYMMSGSEP \ + + filename \ + + PAIRSEPCHAR) + def stopIconFlashers(self): + self.jsIconFlasher1.Stop() + self.jsIconFlasher2.Stop() + self.midiIconFlasher1.Stop() + self.midiIconFlasher2.Stop() + def Destroy(self): + if (not self.locked): + self.stopIconFlashers() + wxFrame.Destroy(self) + + +# Classes used by mainFrame +# Class to poll for connection to server +class connectionTimer(wxTimer): + def __init__(self, parent): + wxTimer.__init__(self) + self.mParent = parent + self.timeCount = 0 + def connect(self): + try: + if (not self.mParent.locked): + self.mParent.mainFrame.fileMenu.Enable(ID_CONNECT, False) + tempConn = socket(AF_INET, SOCK_STREAM) + tempConn.connect((self.mParent.host, self.mParent.port)) + tempConn.setblocking(0) + rcvrList = self.mParent.connection.rcvrList + self.mParent.connection = tempConn + self.Stop() + self.mParent.sTimer.Start(self.mParent.pollTime) + self.mParent.connection.send(rcvrList) + for control in self.mParent.controlList: + control.connection = self.mParent.connection + self.mParent.connected = True + self.mParent.pingCount = 0 + self.mParent.pTimer.Start(PINGPOLLTIME) + if (not self.mParent.locked): + self.mParent.mainFrame.connectIcon.SetBitmap(\ + self.mParent.connectImage) + self.mParent.mainFrame.connectIcon.Refresh() + self.mParent.connection.send(SHOWCOMMAND + \ + SYMMSGSEP + "0" + \ + PAIRSEPCHAR) + self.mParent.mainFrame.Show(True) + except: + self.timeCount = self.timeCount + 1 + def Notify(self): + self.connect() + if (self.timeCount >= TIMEOUT): + self.Stop() + dlg = wxMessageDialog(self.mParent.mainFrame, "Connection Timeout", + "Connection", wxOK) + dlg.ShowModal() + dlg.Destroy() + if (not self.mParent.locked): + self.mParent.mainFrame.fileMenu.Enable(ID_CONNECT, True) + +# Class to poll socket for receive string +class socketTimer(wxTimer): + def __init__(self, parent): + wxTimer.__init__(self) + self.mParent = parent + def Notify(self): + try: + receiveBuffer = self.mParent.connection.recv(16384) + numBytes = len(strip(receiveBuffer)) + if (numBytes > 0): + self.mParent.parseReceiveBuffer(receiveBuffer) + except: + pass + +# Class to check connection status +class pingTimer(wxTimer): + def __init__(self, parent): + wxTimer.__init__(self) + self.mParent = parent + def Notify(self): + try: + self.mParent.connection.send(PINGCOMMAND + SYMMSGSEP + \ + "0" + PAIRSEPCHAR) + + except: + self.Stop() + self.mParent.pingTimeout() + +# Class to poll joystick +class joystickTimer(wxTimer): + def __init__(self, parent): + wxTimer.__init__(self) + self.mParent = parent + def Notify(self): + if (self.mParent.joyID1 > -1): + numEvents1 = joystick.readEvents(self.mParent.joyID1) + if (numEvents1 > 0): + self.mParent.showJoystickActive(1) + for i in range(0, numEvents1): + if (joystick.getEventType(self.mParent.joyID1, i) == 0): + try: + self.mParent.connection.send('joy0axis' + + repr(joystick.getEventNumber( + self.mParent.joyID1, + i)) \ + + SYMMSGSEP \ + + repr(joystick.getEventValue( + self.mParent.joyID1, + i)) \ + + PAIRSEPCHAR) + except: + self.mParent.close() + if (joystick.getEventType(self.mParent.joyID1,i) == 1): + try: + self.mParent.connection.send('joy0button' + + repr(joystick.getEventNumber( + self.mParent.joyID1, + i)) \ + + SYMMSGSEP \ + + repr(joystick.getEventValue( + self.mParent.joyID1, + i)) \ + + PAIRSEPCHAR) + except: + self.mParent.close() + if (self.mParent.joyID2 > -1): + numEvents2 = joystick.readEvents(self.mParent.joyID2) + if (numEvents2 > 0): + self.mParent.showJoystickActive(2) + for i in range(0, numEvents2): + if (joystick.getEventType(self.mParent.joyID2, i) == 0): + try: + self.mParent.connection.send('joy1axis' + + repr(joystick.getEventNumber( + self.mParent.joyID2, + i)) \ + + SYMMSGSEP \ + + repr(joystick.getEventValue( + self.mParent.joyID2, + i)) \ + + PAIRSEPCHAR) + except: + self.mParent.close() + if (joystick.getEventType(self.mParent.joyID2,i) == 1): + try: + self.mParent.connection.send('joy1button' + + repr(joystick.getEventNumber( + self.mParent.joyID2, + i)) \ + + SYMMSGSEP \ + + repr(joystick.getEventValue( + self.mParent.joyID2, + i)) \ + + PAIRSEPCHAR) + except: + self.mParent.close() + +# Class to poll midi +class midiTimer(wxTimer): + def __init__(self, parent): + wxTimer.__init__(self) + self.mParent = parent + def Notify(self): + if (self.mParent.midiID1 > -1): + numEvents1 = midi.readEvents(self.mParent.midiID1) + if (numEvents1 > 0): + self.mParent.showMidiActive(1) + for i in range(0, numEvents1): + midiCommand = midi.getEventCommand(self.mParent.midiID1, i) + midiCommand = hex(midiCommand) + midiP1 = midi.getEventP1(self.mParent.midiID1, i) + midiP2 = midi.getEventP2(self.mParent.midiID1, i) + messageType = midiCommand[2] + channel = repr(atoi(midiCommand[3]) + 1) + try: + if (messageType == MIDINOTEMESSAGE): + self.mParent.connection.send('midi0note' + + SYMMSGSEP \ + + repr(midiP1) \ + + " " \ + + repr(midiP2) \ + + " " \ + + channel \ + + PAIRSEPCHAR) + elif (messageType == MIDICTLMESSAGE): + self.mParent.connection.send('midi0ctl' + + SYMMSGSEP \ + + repr(midiP1) \ + + " " \ + + repr(midiP2) \ + + " " \ + + channel \ + + PAIRSEPCHAR) + elif (messageType == MIDIPGMMESSAGE): + self.mParent.connection.send('midi0pgm' + + SYMMSGSEP \ + + repr(midiP1) \ + + " " \ + + channel \ + + PAIRSEPCHAR) + except: + self.mParent.close() + if (self.mParent.midiID2 > -1): + numEvents2 = midi.readEvents(self.mParent.midiID2) + if (numEvents2 > 0): + self.mParent.showMidiActive(2) + for i in range(0, numEvents2): + midiCommand = midi.getEventCommand(self.mParent.midiID2, i) + midiCommand = hex(midiCommand) + midiP1 = midi.getEventP1(self.mParent.midiID2, i) + midiP2 = midi.getEventP2(self.mParent.midiID2, i) + messageType = midiCommand[2] + channel = repr(atoi(midiCommand[3]) + 1) + try: + if (messageType == MIDINOTEMESSAGE): + self.mParent.connection.send('midi1note' + + SYMMSGSEP \ + + repr(midiP1) \ + + " " \ + + repr(midiP2) \ + + " " \ + + channel \ + + PAIRSEPCHAR) + elif (messageType == MIDICTLMESSAGE): + self.mParent.connection.send('midi1ctl' + + SYMMSGSEP \ + + repr(midiP1) \ + + " " \ + + repr(midiP2) \ + + " " \ + + channel \ + + PAIRSEPCHAR) + elif (messageType == MIDIPGMMESSAGE): + self.mParent.connection.send('midi1pgm' + + SYMMSGSEP \ + + repr(midiP1) \ + + " " \ + + channel \ + + PAIRSEPCHAR) + except: + self.mParent.close() + +# Class to flash icon between 2 bitmaps +class iconFlasher(wxTimer): + def __init__(self, icon, bitmap1, bitmap2, nFlashes): + wxTimer.__init__(self) + self.icon = icon + self.bitmap1 = bitmap1 + self.bitmap2 = bitmap2 + self.nFlashes = nFlashes + self.running = False + def Start(self, ms): + if (not self.running): + self.running = True + self.flashCount = 0 + self.activeBitmap = 1 + wxTimer.Start(self, ms) + def Stop(self): + self.running = False + self.icon.SetBitmap(self.bitmap1) + wxTimer.Stop(self) + def Notify(self): + if (self.flashCount >= self.nFlashes): + self.icon.SetBitmap(self.bitmap1) + self.icon.Refresh() + self.Stop() + else: + if (self.activeBitmap == 1): + self.icon.SetBitmap(self.bitmap2) + self.icon.Refresh() + self.activeBitmap = 2 + self.flashCount = self.flashCount + 1 + else: + self.icon.SetBitmap(self.bitmap1) + self.activeBitmap = 1 + self.icon.Refresh() + +# Class to hold commands (receive names) while not connected +class nullConnection: + def __init__(self): + self.rcvrList = "" + def send(self, receiveBuffer): + (symName, value) = split(receiveBuffer,SYMMSGSEP) + if (symName[0] == COMMANDCHAR): + if (symName == SETRCVRCOMMAND): + self.rcvrList = self.rcvrList + receiveBuffer + def close(self): + pass + +# Class for holding control info for duplicate (sort of emulates file object) +class duplicationContainer: + def __init__(self): + self.list = [] + def write(self, string): + self.list.append(string) + def chomp(self): + for i in range(0, len(self.list)): + self.list[i] = replace(self.list[i], "\n", "") + def getList(self): + return self.list + +# Class for setting options +class optionsDialog(wxDialog): + def __init__(self, parent): + self.parent = parent + wxDialog.__init__(self, parent.mainFrame, -1, "Configure", + wxDefaultPosition, wxDefaultSize, + wxDIALOG_MODAL | wxCAPTION) + + titleText = wxStaticText(self, -1, "Window Title:", + (DEFOPTIONSPOS[0] + 10, + DEFOPTIONSPOS[1] + 20)) + self.titleBox = wxTextCtrl(self, -1, parent.frameTitle, + (titleText.GetPosition()[0] \ + + titleText.GetSize()[0] + 80, + titleText.GetPosition()[1] - 4)) + + addrText = wxStaticText(self, -1, "Connection Address:", + (titleText.GetPosition()[0], + titleText.GetPosition()[1] \ + + titleText.GetSize()[1] + 15)) + self.addrBox = wxTextCtrl(self, -1, parent.host, + (self.titleBox.GetPosition()[0], + addrText.GetPosition()[1] - 4)) + + portText = wxStaticText(self, -1, "Connection Port:", + (addrText.GetPosition()[0], + addrText.GetPosition()[1] \ + + addrText.GetSize()[1] + 15)) + self.portBox = wxTextCtrl(self, -1, repr(parent.port), + (self.titleBox.GetPosition()[0], + portText.GetPosition()[1] - 4)) + + pollText = wxStaticText(self, -1, "Socket Poll Time (ms): ", + (addrText.GetPosition()[0], + portText.GetPosition()[1] \ + + portText.GetSize()[1] + 15)) + self.pollBox = wxTextCtrl(self, -1, repr(parent.pollTime), + (self.titleBox.GetPosition()[0], + pollText.GetPosition()[1] - 4)) + + joyDevText1 = wxStaticText(self, -1, "Joystick Device 0: ", + (addrText.GetPosition()[0], + pollText.GetPosition()[1] \ + + pollText.GetSize()[1] + 15)) + self.joyDevBox1 = wxTextCtrl(self, -1, parent.joyDevice1, + (self.titleBox.GetPosition()[0], + joyDevText1.GetPosition()[1] - 4)) + + joyDevText2 = wxStaticText(self, -1, "Joystick Device 1: ", + (addrText.GetPosition()[0], + joyDevText1.GetPosition()[1] \ + + joyDevText1.GetSize()[1] + 15)) + self.joyDevBox2 = wxTextCtrl(self, -1, parent.joyDevice2, + (self.titleBox.GetPosition()[0], + joyDevText2.GetPosition()[1] - 4)) + + joyPollText = wxStaticText(self, -1, "Joystick Poll Time (ms): ", + (addrText.GetPosition()[0], + joyDevText2.GetPosition()[1] \ + + joyDevText2.GetSize()[1] + 15)) + self.joyPollBox = wxTextCtrl(self, -1, repr(parent.joyPollTime), + (self.titleBox.GetPosition()[0], + joyPollText.GetPosition()[1] - 4)) + + midiDevText1 = wxStaticText(self, -1, "MIDI Device 0: ", + (addrText.GetPosition()[0], + joyPollText.GetPosition()[1] \ + + joyPollText.GetSize()[1] + 15)) + self.midiDevBox1 = wxTextCtrl(self, -1, repr(parent.midiDevice1), + (self.titleBox.GetPosition()[0], + midiDevText1.GetPosition()[1] - 4)) + + midiDevText2 = wxStaticText(self, -1, "MIDI Device 1: ", + (addrText.GetPosition()[0], + midiDevText1.GetPosition()[1] \ + + midiDevText1.GetSize()[1] + 15)) + self.midiDevBox2 = wxTextCtrl(self, -1, repr(parent.midiDevice2), + (self.titleBox.GetPosition()[0], + midiDevText2.GetPosition()[1] - 4)) + + midiPollText = wxStaticText(self, -1, "MIDI Poll Time (ms): ", + (addrText.GetPosition()[0], + midiDevText2.GetPosition()[1] \ + + midiDevText2.GetSize()[1] + 15)) + self.midiPollBox = wxTextCtrl(self, -1, repr(parent.midiPollTime), + (self.titleBox.GetPosition()[0], + midiPollText.GetPosition()[1] - 4)) + + bColorText = wxStaticText(self, -1, "Background Color:", + (addrText.GetPosition()[0], + midiPollText.GetPosition()[1] \ + + midiPollText.GetSize()[1] + 15)) + bColorButton = wxButton(self, -1, "Set", + (self.titleBox.GetPosition()[0], + bColorText.GetPosition()[1] - 4), + self.midiPollBox.GetSize()) + + rect = wxStaticBox(self, -1, "Options", DEFOPTIONSPOS, + (self.addrBox.GetPosition()[0] \ + + self.addrBox.GetSize()[0] + 10, + bColorButton.GetPosition()[1] + \ + bColorButton.GetSize()[1] + 20)) + line = wxStaticLine(self, -1, (DEFOPTIONSPOS[0], + bColorButton.GetPosition()[1] \ + + bColorButton.GetSize()[1] + 30), + (rect.GetSize()[0], 1)) + okButton = wxButton(self, -1, "OK", (0, line.GetPosition()[1] + 10)) + self.SetSize((rect.GetSize()[0] + 15, + okButton.GetPosition()[1] + \ + (FUGEFACTOR * okButton.GetSize()[1]) + \ + (okButton.GetPosition()[1] - line.GetPosition()[1]) + 4)) + okButton.Center(wxHORIZONTAL) + okButton.Move((okButton.GetPosition()[0], line.GetPosition()[1] + 10)) + EVT_BUTTON(self, okButton.GetId(), self.eOK) + EVT_BUTTON(self, bColorButton.GetId(), self.eBColor) + def eOK(self, event): + self.EndModal(wxID_OK) + def eBColor(self, event): + color = getColorFromDialog(self, + self.parent.mainFrame.mainPanel.GetBackgroundColour()) + self.parent.mainFrame.mainPanel.SetBackgroundColour(color) + for control in self.parent.controlList: + if (control.resetBackground): + control.SetBackgroundColour(color) diff --git a/icon.pic b/icon.pic new file mode 100644 index 0000000..26e8bb2 Binary files /dev/null and b/icon.pic differ diff --git a/joystick.xpm b/joystick.xpm new file mode 100644 index 0000000..bd52354 --- /dev/null +++ b/joystick.xpm @@ -0,0 +1,68 @@ +/* XPM */ +static char * joystick_xpm[] = { +"17 16 49 1", +" c None", +". c #000000", +"+ c #9C9C9C", +"@ c #FFFFFF", +"# c #444444", +"$ c #4C4C4C", +"% c #323232", +"& c #464646", +"* c #F9F9F9", +"= c #252525", +"- c #474747", +"; c #E0E0E0", +"> c #DADADA", +", c #E1E1E1", +"' c #7C0000", +") c #380000", +"! c #8A8A8A", +"~ c #DEDEDE", +"{ c #A4A4A4", +"] c #ADADAD", +"^ c #D0D0D0", +"/ c #F7FFFF", +"( c #800000", +"_ c #603B3B", +": c #C4C4C4", +"< c #81ABAB", +"[ c #4C5858", +"} c #969696", +"| c #4E4E4E", +"1 c #E9E9E9", +"2 c #5A5A5A", +"3 c #F4F4F4", +"4 c #BFBFBF", +"5 c #353535", +"6 c #5D5D5D", +"7 c #818181", +"8 c #BDBDBD", +"9 c #131313", +"0 c #181818", +"a c #5E5E5E", +"b c #838383", +"c c #8D8D8D", +"d c #535353", +"e c #E8E8E8", +"f c #696969", +"g c #8B8B8B", +"h c #AAAAAA", +"i c #6A6A6A", +"j c #070707", +" .. ", +" +@@. ", +" +@#. ", +" +@#. ", +" +@#. ", +" +@#. ", +" $%+@#.%% ", +" &%**+@##@@%%= ", +" -%;>,@.@..@')@@.", +"!@~{]^@@.@,/(_@!.", +"-@@@@:,,,,@@@<[}.", +"|12}3@@@]@4@5678.", +"9@@@}2}@@@0ab}c..", +"..dee@@}}.f}g.. ", +" h..he@@i!.. ", +" hj.... "}; diff --git a/joystickA.xpm b/joystickA.xpm new file mode 100644 index 0000000..9e41b76 --- /dev/null +++ b/joystickA.xpm @@ -0,0 +1,45 @@ +/* XPM */ +static char * joystickA_xpm[] = { +"17 16 26 1", +" c None", +". c #000000", +"+ c #008200", +"@ c #00FF08", +"# c #003300", +"$ c #4C4C4C", +"% c #323232", +"& c #464646", +"* c #252525", +"= c #474747", +"- c #00C400", +"; c #7C0000", +"> c #380000", +", c #8A8A8A", +"' c #026602", +") c #009E00", +"! c #800000", +"~ c #603B3B", +"{ c #81ABAB", +"] c #004400", +"^ c #4E4E4E", +"/ c #005600", +"( c #131313", +"_ c #181818", +": c #AAAAAA", +"< c #070707", +" .. ", +" +@@. ", +" +@#. ", +" +@#. ", +" +@#. ", +" +@#. ", +" $%+@#.%% ", +" &%@@+@##@@%%* ", +" =%---@.@..@;>@@.", +",@-'')@@.@-@!~@'.", +"=@@@@+----@@@{]+.", +"^-]/@@@@'@)@#]/).", +"(@@@/]'@@@_]/+'..", +"..]--@@''.]+'.. ", +" :..+-@@]+.. ", +" :<.... "}; diff --git a/joystickX.xpm b/joystickX.xpm new file mode 100644 index 0000000..820e56e --- /dev/null +++ b/joystickX.xpm @@ -0,0 +1,57 @@ +/* XPM */ +static char * joystickX_xpm[] = { +"17 16 38 1", +" c None", +". c #000000", +"+ c #9C9C9C", +"@ c #FFFFFF", +"# c #FF0000", +"$ c #FF8484", +"% c #444444", +"& c #323232", +"* c #383838", +"= c #464646", +"- c #EAEAEA", +"; c #7C8F8F", +"> c #252525", +", c #474747", +"' c #CACACA", +") c #E0E0E0", +"! c #DADADA", +"~ c #7C0000", +"{ c #380000", +"] c #8A8A8A", +"^ c #DEDEDE", +"/ c #A4A4A4", +"( c #603B3B", +"_ c #4C5858", +": c #969696", +"< c #4E4E4E", +"[ c #E9E9E9", +"} c #5A5A5A", +"| c #818181", +"1 c #BDBDBD", +"2 c #131313", +"3 c #8D8D8D", +"4 c #535353", +"5 c #696969", +"6 c #AAAAAA", +"7 c #E8E8E8", +"8 c #6A6A6A", +"9 c #070707", +" .. ", +" +@@. ", +" ##$ +@%.$## ", +" ###$+@%$### ", +" ####$@$#### ", +" $####$####$ ", +" $#######$& ", +" *=-$#####$@@;> ", +" ,')!$#####$~{@@.", +"]@^/$#######$(@].", +",@@$####$####$_:.", +"<[}####$@$####|1.", +"2@@###$@@@$###3..", +"..4##$@::.5$##. ", +" 6..67@@8].. ", +" 69.... "}; diff --git a/log.txt b/log.txt new file mode 100644 index 0000000..e69de29 diff --git a/midi.xpm b/midi.xpm new file mode 100644 index 0000000..cb1215c --- /dev/null +++ b/midi.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * midi_xpm[] = { +"17 16 5 1", +" c None", +". c #000000", +"+ c #808080", +"@ c #FFFFFF", +"# c #C0C0C0", +" ", +" ... ... ... ", +"+++............++", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@@.##@.##@.##@+", +"+@@@.#@@.#@@.#@@+", +"+@@@.#@@.#@@.#@@+", +"+@@@.#@@.#@@.#@@+", +"+@@@.#@@.#@@.#@@+", +".+++.+++.+++.+++.", +"................."}; diff --git a/midiA.xpm b/midiA.xpm new file mode 100644 index 0000000..6779a39 --- /dev/null +++ b/midiA.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * midiA_xpm[] = { +"17 16 5 1", +" c None", +". c #000000", +"+ c #045B0E", +"@ c #00FF08", +"# c #07BA1F", +" ", +" ... ... ... ", +"+++............++", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@...#...#...#@+", +"+@@@.##@.##@.##@+", +"+@@@.#@@.#@@.#@@+", +"+@@@.#@@.#@@.#@@+", +"+@@@.#@@.#@@.#@@+", +"+@@@.#@@.#@@.#@@+", +".+++.+++.+++.+++.", +"................."}; diff --git a/midiX.xpm b/midiX.xpm new file mode 100644 index 0000000..8ee69f9 --- /dev/null +++ b/midiX.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char * midiX_xpm[] = { +"17 16 7 1", +" c None", +". c #000000", +"+ c #808080", +"@ c #FF0000", +"# c #FF8484", +"$ c #FFFFFF", +"% c #C0C0C0", +" ", +" ... ... ... ", +"+++@@#.....#@@.++", +"+$$@@@#...#@@@%$+", +"+$$@@@@#.#@@@@%$+", +"+$$#@@@@#@@@@#%$+", +"+$$.#@@@@@@@#.%$+", +"+$$..#@@@@@#..%$+", +"+$$..#@@@@@#..%$+", +"+$$$#@@@@@@@#%%$+", +"+$$#@@@@#@@@@#$$+", +"+$$@@@@#.#@@@@$$+", +"+$$@@@#$.%#@@@$$+", +"+$$@@#$$.%$#@@$$+", +".+++.+++.+++.+++.", +"................."}; diff --git a/src/Makefile.Linux b/src/Makefile.Linux new file mode 100644 index 0000000..999bc91 --- /dev/null +++ b/src/Makefile.Linux @@ -0,0 +1,48 @@ +include makefile + +current: all + +all: gripd.pd_linux joystickmodule.so midimodule.so + +LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \ + -Wall -W -Wshadow -Wstrict-prototypes -Werror \ + -Wno-unused -Wno-parentheses -Wno-switch +MIDIDEFINES = -D$(MIDIOSSUBTYPE) -DLINUX +MIDICOMPILEFLAGS = -O6 -I./midiio/include $(MIDIDEFINES) +MIDILINKFLAGS = -L$(SYSTEMLIBDIR) -lpthread -L./midiio/lib -lmidiio +ifeq ($(MIDIOSSUBTYPE), ALSA) +MIDILINKFLAGS += -lasound +endif + +gripd.pd_linux: + cc $(LINUXCFLAGS) $(PDINCLUDE) -o gripd.o -c gripd.c + ld -export_dynamic -lm -shared -o gripd.pd_linux gripd.o -lc -lm + strip --strip-unneeded gripd.pd_linux + cp gripd.pd_linux .. + +joystickmodule.so: +ifeq ($(JOYSTICK), TRUE) + cc -c joystick.c + cc $(LINUXPYTHONINCLUDE) -c -DHAVE_CONFIG_H joystick_wrap.c + ld -shared joystick.o joystick_wrap.o -o joystickmodule.so + cp joystickmodule.so .. +endif + echo "joystick = "$(JOYSTICK) > ../gripd.opt + +midimodule.so: +ifeq ($(MIDI), TRUE) + make -f Makefile.midiioLibrary.$(MIDIOSSUBTYPE) + g++ -c $(MIDICOMPILEFLAGS) midi.cpp + g++ $(LINUXPYTHONINCLUDE) -c -DHAVE_CONFIG_H midi_wrap.c + g++ -shared midi.o midi_wrap.o $(MIDILINKFLAGS) -o midimodule.so + cp midimodule.so .. +endif + echo "midi = "$(MIDI) >> ../gripd.opt + +linux_clean: + rm *.o + rm gripd.pd_linux + rm joystickmodule.so + rm midimodule.so + make -f Makefile.midiioLibrary.$(MIDIOSSUBTYPE) clean + diff --git a/src/Makefile.NT b/src/Makefile.NT new file mode 100644 index 0000000..4974592 --- /dev/null +++ b/src/Makefile.NT @@ -0,0 +1,86 @@ +!INCLUDE makefile + +current: all +all: gripd.dll joystick.dll midi.dll + +PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo + +PDNTINCLUDE = /I. /I\tcl\include /I$(PDNTSRCDIR) /I$(VC)\include +JOYINCLUDE = /I$(PYTHONHOME)\include /I$(VC)\INCLUDE +MIDIINCLUDE = /I$(PYTHONHOME)\include /I$(VC)\INCLUDE /I.\midiio\include +PDNTLIB = $(VC)\lib\libc.lib \ + $(VC)\lib\oldnames.lib \ + $(VC)\lib\kernel32.lib \ + $(VC)\lib\wsock32.lib \ + $(VC)\lib\uuid.lib \ + $(PDNTLDIR)\pd.lib +JOYLIBS = $(VC)\LIB\kernel32.lib \ + $(VC)\LIB\advapi32.lib \ + $(VC)\LIB\user32.lib \ + $(VC)\LIB\gdi32.lib \ + $(VC)\LIB\libcmt.lib \ + $(VC)\LIB\comdlg32.lib \ + $(VC)\LIB\oldnames.lib \ + $(VC)\LIB\winmm.lib \ + $(VC)\LIB\winspool.lib \ + $(PYTHONHOME)\libs\python$(PYTHONVER).lib +MIDILIBS = midiio\lib\midiio.lib \ + $(PYTHONHOME)\libs\python$(PYTHONVER).lib \ + $(VC)\lib\kernel32.lib \ + $(VC)\lib\advapi32.lib \ + $(VC)\lib\user32.lib \ + $(VC)\lib\gdi32.lib \ + $(VC)\lib\comdlg32.lib \ + $(VC)\lib\oldnames.lib \ + $(VC)\lib\winmm.lib \ + $(VC)\lib\winspool.lib +JOYLOPT = -debug:full -debugtype:cv /NODEFAULTLIB /RELEASE /NOLOGO \ + /MACHINE:IX86 -entry:_DllMainCRTStartup@12 -dll +MIDILOPT = -debug:full -debugtype:cv /RELEASE /NOLOGO /NODEFAULTLIB:msvcrt.lib \ + /MACHINE:IX86 -entry:_DllMainCRTStartup@12 -dll + +gripd.dll: + cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c gripd.c + link /dll /export:gripd_setup gripd.obj $(PDNTLIB) + copy gripd.dll .. + +joystick.dll: +!IF "$(JOYSTICK)" == "TRUE" + cl /TP /DNT /c $(JOYINCLUDE) joystick.c + cl /Z7 /Od /c /nologo /D__WIN32__ $(JOYINCLUDE) joystick_wrap.c + link $(JOYLOPT) -out:joystick.dll $(JOYLIBS) joystick_wrap.obj \ + joystick.obj + copy joystick.dll .. +!ENDIF + echo joystick = $(JOYSTICK) > ..\gripd.opt + +midi.dll: +!IF "$(MIDI)" == "TRUE" + nmake -f Makefile.midiioLibrary.NT + cl /DVISUAL /TP /DNT /c /GX $(MIDIINCLUDE) midi.cpp + cl /TP /DVISUAL /Z7 /Od /c /nologo /D__WIN32__ $(MIDIINCLUDE) midi_wrap.c + link $(MIDILOPT) -out:midi.dll $(MIDILIBS) midi_wrap.obj midi.obj + copy midi.dll .. +!ENDIF + echo midi = $(MIDI) >> ..\gripd.opt + +nt_clean: + del gripd.obj + del gripd.exp + del gripd.lib + del joystick.pdb + del joystick.obj + del joystick.lib + del joystick.exp + del joystick_wrap.obj + del midi.pdb + del midi.obj + del midi.lib + del midi.exp + del midi_wrap.obj + del gripd.dll + del joystick.dll + del midi.dll + nmake -f Makefile.midiioLibrary.NT CLEAN + + diff --git a/src/Makefile.midiioLibrary.ALSA b/src/Makefile.midiioLibrary.ALSA new file mode 100644 index 0000000..5a5a7b2 --- /dev/null +++ b/src/Makefile.midiioLibrary.ALSA @@ -0,0 +1,205 @@ +## midiio library GNU makefile for linux. +## +## Programmer: Craig Stuart Sapp +## Creation Date: Sat Nov 2 19:49:57 PST 2002 +## Last Modified: Sat Nov 2 19:50:00 PST 2002 +## Filename: ...midiio/Makefile.library +## +## Description: This Makefile creates the midiio library lib/libmidiio.a +## for linux, using gcc 2.7.2.1 or higher +## +## To run this makefile, type (without quotes) "make -f Makefile.library" +## + +########################################################################### +# # +# # +# Operating System OSTYPEs available in the midiio library compilation: # +# +# LINUX = Linux running on intel computers +# VISUAL = Windows 95/NT using Microsoft Visual C++ 5/6 +# OSX = Apple Mac OS X (10.2 or higher when it is ready) +# +# The file "sigConfiguration.h" in the include directory contains additional +# defines which will be activated by the OS given by the OSTYPE variable +# below. Look at the sigConfiguration.h file for various things which need +# to be defined specifically for each OS. +# +OSTYPE = LINUX + +# The OSSUBTYPE is for determining which type of sound drivers +# are being used in linux. There are three possibilities: +# OSSUBTYPE = ALSA # ALSA 0.9 interface (http://www.alsa-project.org) +# OSSUBTYPE = ALSA05 # ALSA 0.5 interface (http://www.alsa-project.org) +# OSSUBTYPE = OSS # OSS interface (http://www.4front-tech.com) +# Note: The Improv library accesses the internal/external MIDI devices +# in OSS, but only the external MIDI devices in ALSA. OSS can be +# emulated in ALSA 0.9. +# +OSSUBTYPE = ALSA + +OBJDIR = ./midiio/obj +SRCDIR = ./midiio/src +INCDIR = ./midiio/include +LIBDIR = ./midiio/lib +LIBFILE = libmidiio.a + +COMPILER = g++ +# MAC OSX 10.2 needs this compiler: +# COMPILER = g++2 + +DEFINES = $(addprefix -D,$(OSTYPE)) $(addprefix -D,$(OSSUBTYPE)) +FLAGS = -Wall -c -O3 $(DEFINES) -I$(INCDIR) + +# # +# End of user-modifiable variables. # +# # +########################################################################### + + +# setting up the directory paths to search for dependency files +vpath %.h $(INCDIR):$(SRCDIR) +vpath %.cpp $(SRCDIR):$(INCDIR) +vpath %.o $(OBJDIR) + +# generating a list of the object files +OBJS = $(notdir $(patsubst %.cpp,%.o,$(wildcard $(SRCDIR)/*.cpp))) + +# targets which don't actually refer to files +.PHONY : all linux makeobjdir + + +########################################################################### +# # +# Hardware Configurations: # +# # + +all: makeobjdir $(OBJS) + + ifeq ($(OSTYPE),LINUX) + @echo Making midiio library file for linux ... + -mkdir -p $(LIBDIR) + -rm -f $(LIBDIR)/$(LIBFILE) + ar r $(LIBDIR)/$(LIBFILE) $(OBJDIR)/*.o + ranlib $(LIBDIR)/$(LIBFILE) + endif + + ifeq ($(OSTYPE),VISUAL) + echo "this makefile doesn't work with Visual C++." + endif + +clean: + @echo Erasing object files: + -rm -f $(OBJDIR)/*.o + @echo Erasing obj directory: + -rmdir $(OBJDIR) + +makeobjdir: + -mkdir -p $(OBJDIR) + +# defining an explicit rule for object file dependencies +%.o : %.cpp + $(COMPILER) $(FLAGS) -o $(OBJDIR)/$(notdir $@) $< + + +# # +########################################################################### + + + +########################################################################### +# # +# Dependencies -- generated with the following command in # +# the src directory (in csh shell): # +# # +# foreach i (*.cpp) # +# cc -I../include -MM $i | sed 's/\.\.\/include\///g' # +# echo "" # +# end # +# # + +FileIO.o: FileIO.cpp FileIO.h sigConfiguration.h + +MidiFile.o: MidiFile.cpp MidiFile.h FileIO.h Array.h Collection.h \ + Collection.cpp Array.cpp + +MidiFileWrite.o: MidiFileWrite.cpp MidiFileWrite.h FileIO.h SigTimer.h + +MidiIO.o: MidiIO.cpp MidiIO.h MidiInput.h MidiInPort.h MidiMessage.h \ + MidiInPort_unsupported.h CircularBuffer.h CircularBuffer.cpp \ + Array.h Collection.h Collection.cpp Array.cpp MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h FileIO.h SigTimer.h + +MidiInPort_alsa.o: MidiInPort_alsa.cpp + +MidiInPort_alsa05.o: MidiInPort_alsa05.cpp + +MidiInPort_linux.o: MidiInPort_linux.cpp + +MidiInPort_oss.o: MidiInPort_oss.cpp + +MidiInPort_unsupported.o: MidiInPort_unsupported.cpp \ + MidiInPort_unsupported.h MidiMessage.h CircularBuffer.h \ + CircularBuffer.cpp Array.h Collection.h Collection.cpp \ + Array.cpp + +MidiInPort_visual.o: MidiInPort_visual.cpp + +MidiInput.o: MidiInput.cpp MidiInput.h MidiInPort.h MidiMessage.h \ + MidiInPort_unsupported.h CircularBuffer.h CircularBuffer.cpp \ + Array.h Collection.h Collection.cpp Array.cpp + +MidiMessage.o: MidiMessage.cpp MidiMessage.h + +MidiOutPort_alsa.o: MidiOutPort_alsa.cpp + +MidiOutPort_linux.o: MidiOutPort_linux.cpp + +MidiOutPort_oss.o: MidiOutPort_oss.cpp + +MidiOutPort_unsupported.o: MidiOutPort_unsupported.cpp \ + MidiOutPort_unsupported.h + +MidiOutPort_visual.o: MidiOutPort_visual.cpp + +MidiOutput.o: MidiOutput.cpp MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h FileIO.h SigTimer.h Array.h Collection.h \ + Collection.cpp Array.cpp + +MidiPerform.o: MidiPerform.cpp MidiPerform.h MidiFile.h FileIO.h Array.h \ + Collection.h Collection.cpp Array.cpp CircularBuffer.h \ + CircularBuffer.cpp SigTimer.h MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h + +MidiPort.o: MidiPort.cpp MidiPort.h MidiInPort.h MidiMessage.h \ + MidiInPort_unsupported.h CircularBuffer.h CircularBuffer.cpp \ + Array.h Collection.h Collection.cpp Array.cpp MidiOutPort.h \ + MidiOutPort_unsupported.h + +MultiStageEvent.o: MultiStageEvent.cpp MultiStageEvent.h Event.h \ + OneStageEvent.h MidiEvent.h TwoStageEvent.h NoteEvent.h \ + EventBuffer.h CircularBuffer.h CircularBuffer.cpp MidiOutput.h \ + MidiOutPort.h MidiOutPort_unsupported.h FileIO.h SigTimer.h Array.h \ + Collection.h Collection.cpp Array.cpp FunctionEvent.h + +Options.o: Options.cpp Options.h Array.h Collection.h Collection.cpp \ + Array.cpp Options_private.h + +Options_private.o: Options_private.cpp Options_private.h + +Sequencer_alsa.o: Sequencer_alsa.cpp + +Sequencer_alsa05.o: Sequencer_alsa05.cpp + +Sequencer_oss.o: Sequencer_oss.cpp + +SigTimer.o: SigTimer.cpp SigTimer.h + +Voice.o: Voice.cpp Voice.h MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h FileIO.h SigTimer.h Array.h Collection.h \ + Collection.cpp Array.cpp + + + + + diff --git a/src/Makefile.midiioLibrary.NT b/src/Makefile.midiioLibrary.NT new file mode 100644 index 0000000..a0900b0 --- /dev/null +++ b/src/Makefile.midiioLibrary.NT @@ -0,0 +1,462 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on midiio.dsp +!IF "$(CFG)" == "" +CFG = midiio - Win32 Release +!ENDIF + +!IF "$(CFG)" != "midiio - Win32 Release" && "$(CFG)" != "midiio - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "midiio.mak" CFG="midiio - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "midiio - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "midiio - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "midiio - Win32 Release" + +OUTDIR=.\midiio\lib +INTDIR=.\midiio\obj +# Begin Custom Macros +OutDir=.\midiio\lib +# End Custom Macros + +ALL : "$(OUTDIR)\midiio.lib" + + +CLEAN : + -@erase "$(INTDIR)\Array.obj" + -@erase "$(INTDIR)\CircularBuffer.obj" + -@erase "$(INTDIR)\Collection.obj" + -@erase "$(INTDIR)\FileIO.obj" + -@erase "$(INTDIR)\MidiFile.obj" + -@erase "$(INTDIR)\MidiFileWrite.obj" + -@erase "$(INTDIR)\MidiInPort_alsa.obj" + -@erase "$(INTDIR)\MidiInPort_alsa05.obj" + -@erase "$(INTDIR)\MidiInPort_linux.obj" + -@erase "$(INTDIR)\MidiInPort_oss.obj" + -@erase "$(INTDIR)\MidiInPort_unsupported.obj" + -@erase "$(INTDIR)\MidiInPort_visual.obj" + -@erase "$(INTDIR)\MidiInput.obj" + -@erase "$(INTDIR)\MidiIO.obj" + -@erase "$(INTDIR)\MidiMessage.obj" + -@erase "$(INTDIR)\MidiOutPort_alsa.obj" + -@erase "$(INTDIR)\MidiOutPort_linux.obj" + -@erase "$(INTDIR)\MidiOutPort_oss.obj" + -@erase "$(INTDIR)\MidiOutPort_unsupported.obj" + -@erase "$(INTDIR)\MidiOutPort_visual.obj" + -@erase "$(INTDIR)\MidiOutput.obj" + -@erase "$(INTDIR)\MidiPort.obj" + -@erase "$(INTDIR)\Options.obj" + -@erase "$(INTDIR)\Options_private.obj" + -@erase "$(INTDIR)\Sequencer_alsa.obj" + -@erase "$(INTDIR)\Sequencer_alsa05.obj" + -@erase "$(INTDIR)\Sequencer_oss.obj" + -@erase "$(INTDIR)\SigTimer.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\Voice.obj" + -@erase "$(INTDIR)\midiio.pch" + -@erase "$(OUTDIR)\midiio.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /ML /W3 /GX /O2 /I ".\midiio\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "VISUAL" /Fp"$(INTDIR)\midiio.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\midiio.bsc" +BSC32_SBRS= \ + +LIB32=link.exe -lib +LIB32_FLAGS=/nologo /out:"$(OUTDIR)\midiio.lib" +LIB32_OBJS= \ + "$(INTDIR)\Array.obj" \ + "$(INTDIR)\CircularBuffer.obj" \ + "$(INTDIR)\Collection.obj" \ + "$(INTDIR)\FileIO.obj" \ + "$(INTDIR)\MidiFile.obj" \ + "$(INTDIR)\MidiFileWrite.obj" \ + "$(INTDIR)\MidiInPort_alsa.obj" \ + "$(INTDIR)\MidiInPort_alsa05.obj" \ + "$(INTDIR)\MidiInPort_linux.obj" \ + "$(INTDIR)\MidiInPort_oss.obj" \ + "$(INTDIR)\MidiInPort_unsupported.obj" \ + "$(INTDIR)\MidiInPort_visual.obj" \ + "$(INTDIR)\MidiInput.obj" \ + "$(INTDIR)\MidiIO.obj" \ + "$(INTDIR)\MidiMessage.obj" \ + "$(INTDIR)\MidiOutPort_alsa.obj" \ + "$(INTDIR)\MidiOutPort_linux.obj" \ + "$(INTDIR)\MidiOutPort_oss.obj" \ + "$(INTDIR)\MidiOutPort_unsupported.obj" \ + "$(INTDIR)\MidiOutPort_visual.obj" \ + "$(INTDIR)\MidiOutput.obj" \ + "$(INTDIR)\MidiPort.obj" \ + "$(INTDIR)\Options.obj" \ + "$(INTDIR)\Options_private.obj" \ + "$(INTDIR)\Sequencer_alsa.obj" \ + "$(INTDIR)\Sequencer_alsa05.obj" \ + "$(INTDIR)\Sequencer_oss.obj" \ + "$(INTDIR)\SigTimer.obj" \ + "$(INTDIR)\Voice.obj" + +"$(OUTDIR)\midiio.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS) + $(LIB32) @<< + $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) +<< + +!ELSEIF "$(CFG)" == "midiio - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\midiio.lib" + + +CLEAN : + -@erase "$(INTDIR)\Array.obj" + -@erase "$(INTDIR)\CircularBuffer.obj" + -@erase "$(INTDIR)\Collection.obj" + -@erase "$(INTDIR)\FileIO.obj" + -@erase "$(INTDIR)\MidiFile.obj" + -@erase "$(INTDIR)\MidiFileWrite.obj" + -@erase "$(INTDIR)\MidiInPort_alsa.obj" + -@erase "$(INTDIR)\MidiInPort_alsa05.obj" + -@erase "$(INTDIR)\MidiInPort_linux.obj" + -@erase "$(INTDIR)\MidiInPort_oss.obj" + -@erase "$(INTDIR)\MidiInPort_unsupported.obj" + -@erase "$(INTDIR)\MidiInPort_visual.obj" + -@erase "$(INTDIR)\MidiInput.obj" + -@erase "$(INTDIR)\MidiIO.obj" + -@erase "$(INTDIR)\MidiMessage.obj" + -@erase "$(INTDIR)\MidiOutPort_alsa.obj" + -@erase "$(INTDIR)\MidiOutPort_linux.obj" + -@erase "$(INTDIR)\MidiOutPort_oss.obj" + -@erase "$(INTDIR)\MidiOutPort_unsupported.obj" + -@erase "$(INTDIR)\MidiOutPort_visual.obj" + -@erase "$(INTDIR)\MidiOutput.obj" + -@erase "$(INTDIR)\MidiPort.obj" + -@erase "$(INTDIR)\Options.obj" + -@erase "$(INTDIR)\Options_private.obj" + -@erase "$(INTDIR)\Sequencer_alsa.obj" + -@erase "$(INTDIR)\Sequencer_alsa05.obj" + -@erase "$(INTDIR)\Sequencer_oss.obj" + -@erase "$(INTDIR)\SigTimer.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(INTDIR)\Voice.obj" + -@erase "$(OUTDIR)\midiio.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od /I ".\midiio\include" /D "VISUAL" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fp"$(INTDIR)\midiio.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\midiio.bsc" +BSC32_SBRS= \ + +LIB32=link.exe -lib +LIB32_FLAGS=/nologo /out:"$(OUTDIR)\midiio.lib" +LIB32_OBJS= \ + "$(INTDIR)\Array.obj" \ + "$(INTDIR)\CircularBuffer.obj" \ + "$(INTDIR)\Collection.obj" \ + "$(INTDIR)\FileIO.obj" \ + "$(INTDIR)\MidiFile.obj" \ + "$(INTDIR)\MidiFileWrite.obj" \ + "$(INTDIR)\MidiInPort_alsa.obj" \ + "$(INTDIR)\MidiInPort_alsa05.obj" \ + "$(INTDIR)\MidiInPort_linux.obj" \ + "$(INTDIR)\MidiInPort_oss.obj" \ + "$(INTDIR)\MidiInPort_unsupported.obj" \ + "$(INTDIR)\MidiInPort_visual.obj" \ + "$(INTDIR)\MidiInput.obj" \ + "$(INTDIR)\MidiIO.obj" \ + "$(INTDIR)\MidiMessage.obj" \ + "$(INTDIR)\MidiOutPort_alsa.obj" \ + "$(INTDIR)\MidiOutPort_linux.obj" \ + "$(INTDIR)\MidiOutPort_oss.obj" \ + "$(INTDIR)\MidiOutPort_unsupported.obj" \ + "$(INTDIR)\MidiOutPort_visual.obj" \ + "$(INTDIR)\MidiOutput.obj" \ + "$(INTDIR)\MidiPort.obj" \ + "$(INTDIR)\Options.obj" \ + "$(INTDIR)\Options_private.obj" \ + "$(INTDIR)\Sequencer_alsa.obj" \ + "$(INTDIR)\Sequencer_alsa05.obj" \ + "$(INTDIR)\Sequencer_oss.obj" \ + "$(INTDIR)\SigTimer.obj" \ + "$(INTDIR)\Voice.obj" + +"$(OUTDIR)\midiio.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS) + $(LIB32) @<< + $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) +<< + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("midiiolib.dep") +!INCLUDE "midiiolib.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "midiio - Win32 Release" || "$(CFG)" == "midiio - Win32 Debug" +SOURCE=".\midiio\include\Array.cpp" + +"$(INTDIR)\Array.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\include\CircularBuffer.cpp" + +"$(INTDIR)\CircularBuffer.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\include\Collection.cpp" + +"$(INTDIR)\Collection.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\FileIO.cpp" + +"$(INTDIR)\FileIO.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiFile.cpp" + +"$(INTDIR)\MidiFile.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiFileWrite.cpp" + +"$(INTDIR)\MidiFileWrite.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInPort_alsa.cpp" + +"$(INTDIR)\MidiInPort_alsa.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInPort_alsa05.cpp" + +"$(INTDIR)\MidiInPort_alsa05.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInPort_linux.cpp" + +"$(INTDIR)\MidiInPort_linux.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInPort_oss.cpp" + +"$(INTDIR)\MidiInPort_oss.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInPort_unsupported.cpp" + +"$(INTDIR)\MidiInPort_unsupported.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\CircularBuffer.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInPort_visual.cpp" + +"$(INTDIR)\MidiInPort_visual.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiInput.cpp" + +"$(INTDIR)\MidiInput.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiIO.cpp" + +"$(INTDIR)\MidiIO.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiMessage.cpp" + +"$(INTDIR)\MidiMessage.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiOutPort_alsa.cpp" + +"$(INTDIR)\MidiOutPort_alsa.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiOutPort_linux.cpp" + +"$(INTDIR)\MidiOutPort_linux.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiOutPort_oss.cpp" + +"$(INTDIR)\MidiOutPort_oss.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiOutPort_unsupported.cpp" + +"$(INTDIR)\MidiOutPort_unsupported.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiOutPort_visual.cpp" + +"$(INTDIR)\MidiOutPort_visual.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiOutput.cpp" + +"$(INTDIR)\MidiOutput.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\MidiPort.cpp" + +"$(INTDIR)\MidiPort.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\Options.cpp" + +"$(INTDIR)\Options.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\Options_private.cpp" + +"$(INTDIR)\Options_private.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\Sequencer_alsa.cpp" + +"$(INTDIR)\Sequencer_alsa.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\Sequencer_alsa05.cpp" + +"$(INTDIR)\Sequencer_alsa05.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\Sequencer_oss.cpp" + +"$(INTDIR)\Sequencer_oss.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\SigTimer.cpp" + +"$(INTDIR)\SigTimer.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +SOURCE=".\midiio\src\Voice.cpp" + +"$(INTDIR)\Voice.obj" : $(SOURCE) "$(INTDIR)" ".\midiio\include\Array.cpp" ".\midiio\include\Collection.cpp" + $(CPP) $(CPP_PROJ) $(SOURCE) + + + +!ENDIF + diff --git a/src/Makefile.midiioLibrary.OSS b/src/Makefile.midiioLibrary.OSS new file mode 100644 index 0000000..2f1e6e2 --- /dev/null +++ b/src/Makefile.midiioLibrary.OSS @@ -0,0 +1,205 @@ +## midiio library GNU makefile for linux. +## +## Programmer: Craig Stuart Sapp +## Creation Date: Sat Nov 2 19:49:57 PST 2002 +## Last Modified: Sat Nov 2 19:50:00 PST 2002 +## Filename: ...midiio/Makefile.library +## +## Description: This Makefile creates the midiio library lib/libmidiio.a +## for linux, using gcc 2.7.2.1 or higher +## +## To run this makefile, type (without quotes) "make -f Makefile.library" +## + +########################################################################### +# # +# # +# Operating System OSTYPEs available in the midiio library compilation: # +# +# LINUX = Linux running on intel computers +# VISUAL = Windows 95/NT using Microsoft Visual C++ 5/6 +# OSX = Apple Mac OS X (10.2 or higher when it is ready) +# +# The file "sigConfiguration.h" in the include directory contains additional +# defines which will be activated by the OS given by the OSTYPE variable +# below. Look at the sigConfiguration.h file for various things which need +# to be defined specifically for each OS. +# +OSTYPE = LINUX + +# The OSSUBTYPE is for determining which type of sound drivers +# are being used in linux. There are three possibilities: +# OSSUBTYPE = ALSA # ALSA 0.9 interface (http://www.alsa-project.org) +# OSSUBTYPE = ALSA05 # ALSA 0.5 interface (http://www.alsa-project.org) +# OSSUBTYPE = OSS # OSS interface (http://www.4front-tech.com) +# Note: The Improv library accesses the internal/external MIDI devices +# in OSS, but only the external MIDI devices in ALSA. OSS can be +# emulated in ALSA 0.9. +# +OSSUBTYPE = OSS + +OBJDIR = ./midiio/obj +SRCDIR = ./midiio/src +INCDIR = ./midiio/include +LIBDIR = ./midiio/lib +LIBFILE = libmidiio.a + +COMPILER = g++ +# MAC OSX 10.2 needs this compiler: +# COMPILER = g++2 + +DEFINES = $(addprefix -D,$(OSTYPE)) $(addprefix -D,$(OSSUBTYPE)) +FLAGS = -Wall -c -O3 $(DEFINES) -I$(INCDIR) + +# # +# End of user-modifiable variables. # +# # +########################################################################### + + +# setting up the directory paths to search for dependency files +vpath %.h $(INCDIR):$(SRCDIR) +vpath %.cpp $(SRCDIR):$(INCDIR) +vpath %.o $(OBJDIR) + +# generating a list of the object files +OBJS = $(notdir $(patsubst %.cpp,%.o,$(wildcard $(SRCDIR)/*.cpp))) + +# targets which don't actually refer to files +.PHONY : all linux makeobjdir + + +########################################################################### +# # +# Hardware Configurations: # +# # + +all: makeobjdir $(OBJS) + + ifeq ($(OSTYPE),LINUX) + @echo Making midiio library file for linux ... + -mkdir -p $(LIBDIR) + -rm -f $(LIBDIR)/$(LIBFILE) + ar r $(LIBDIR)/$(LIBFILE) $(OBJDIR)/*.o + ranlib $(LIBDIR)/$(LIBFILE) + endif + + ifeq ($(OSTYPE),VISUAL) + echo "this makefile doesn't work with Visual C++." + endif + +clean: + @echo Erasing object files: + -rm -f $(OBJDIR)/*.o + @echo Erasing obj directory: + -rmdir $(OBJDIR) + +makeobjdir: + -mkdir -p $(OBJDIR) + +# defining an explicit rule for object file dependencies +%.o : %.cpp + $(COMPILER) $(FLAGS) -o $(OBJDIR)/$(notdir $@) $< + + +# # +########################################################################### + + + +########################################################################### +# # +# Dependencies -- generated with the following command in # +# the src directory (in csh shell): # +# # +# foreach i (*.cpp) # +# cc -I../include -MM $i | sed 's/\.\.\/include\///g' # +# echo "" # +# end # +# # + +FileIO.o: FileIO.cpp FileIO.h sigConfiguration.h + +MidiFile.o: MidiFile.cpp MidiFile.h FileIO.h Array.h Collection.h \ + Collection.cpp Array.cpp + +MidiFileWrite.o: MidiFileWrite.cpp MidiFileWrite.h FileIO.h SigTimer.h + +MidiIO.o: MidiIO.cpp MidiIO.h MidiInput.h MidiInPort.h MidiMessage.h \ + MidiInPort_unsupported.h CircularBuffer.h CircularBuffer.cpp \ + Array.h Collection.h Collection.cpp Array.cpp MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h FileIO.h SigTimer.h + +MidiInPort_alsa.o: MidiInPort_alsa.cpp + +MidiInPort_alsa05.o: MidiInPort_alsa05.cpp + +MidiInPort_linux.o: MidiInPort_linux.cpp + +MidiInPort_oss.o: MidiInPort_oss.cpp + +MidiInPort_unsupported.o: MidiInPort_unsupported.cpp \ + MidiInPort_unsupported.h MidiMessage.h CircularBuffer.h \ + CircularBuffer.cpp Array.h Collection.h Collection.cpp \ + Array.cpp + +MidiInPort_visual.o: MidiInPort_visual.cpp + +MidiInput.o: MidiInput.cpp MidiInput.h MidiInPort.h MidiMessage.h \ + MidiInPort_unsupported.h CircularBuffer.h CircularBuffer.cpp \ + Array.h Collection.h Collection.cpp Array.cpp + +MidiMessage.o: MidiMessage.cpp MidiMessage.h + +MidiOutPort_alsa.o: MidiOutPort_alsa.cpp + +MidiOutPort_linux.o: MidiOutPort_linux.cpp + +MidiOutPort_oss.o: MidiOutPort_oss.cpp + +MidiOutPort_unsupported.o: MidiOutPort_unsupported.cpp \ + MidiOutPort_unsupported.h + +MidiOutPort_visual.o: MidiOutPort_visual.cpp + +MidiOutput.o: MidiOutput.cpp MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h FileIO.h SigTimer.h Array.h Collection.h \ + Collection.cpp Array.cpp + +MidiPerform.o: MidiPerform.cpp MidiPerform.h MidiFile.h FileIO.h Array.h \ + Collection.h Collection.cpp Array.cpp CircularBuffer.h \ + CircularBuffer.cpp SigTimer.h MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h + +MidiPort.o: MidiPort.cpp MidiPort.h MidiInPort.h MidiMessage.h \ + MidiInPort_unsupported.h CircularBuffer.h CircularBuffer.cpp \ + Array.h Collection.h Collection.cpp Array.cpp MidiOutPort.h \ + MidiOutPort_unsupported.h + +MultiStageEvent.o: MultiStageEvent.cpp MultiStageEvent.h Event.h \ + OneStageEvent.h MidiEvent.h TwoStageEvent.h NoteEvent.h \ + EventBuffer.h CircularBuffer.h CircularBuffer.cpp MidiOutput.h \ + MidiOutPort.h MidiOutPort_unsupported.h FileIO.h SigTimer.h Array.h \ + Collection.h Collection.cpp Array.cpp FunctionEvent.h + +Options.o: Options.cpp Options.h Array.h Collection.h Collection.cpp \ + Array.cpp Options_private.h + +Options_private.o: Options_private.cpp Options_private.h + +Sequencer_alsa.o: Sequencer_alsa.cpp + +Sequencer_alsa05.o: Sequencer_alsa05.cpp + +Sequencer_oss.o: Sequencer_oss.cpp + +SigTimer.o: SigTimer.cpp SigTimer.h + +Voice.o: Voice.cpp Voice.h MidiOutput.h MidiOutPort.h \ + MidiOutPort_unsupported.h FileIO.h SigTimer.h Array.h Collection.h \ + Collection.cpp Array.cpp + + + + + diff --git a/src/gripd.c b/src/gripd.c new file mode 100644 index 0000000..fce1aa5 --- /dev/null +++ b/src/gripd.c @@ -0,0 +1,1031 @@ +/* GrIPD v0.1. - Graphical Interface for Pure Data +** Copyright (C) 2003 Joseph A. Sarlo +** +** This program is free software; you can redistribute it and/orsig +** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** jsarlo@ucsd.edu +*/ + +#include "gripd.h" + +void gripd_setup(void) +{ + post (" \n"); + post (" .______________________________________."); + post (" | |"); + post (" | GrIPD: v%s |", VERSION); + post (" | Graphical Interface for Pure Data |"); + post (" | (C) Copyright 2003 Joseph A. Sarlo |"); + post (" | GNU General Public License |"); + post (" |______________________________________|"); + post (" \n"); +#ifndef NT + signal(SIGCHLD, gripd_sigChild); +#endif + gripd_class = class_new(gensym("gripd"), (t_newmethod)gripd_new, + (t_method)gripd_free, sizeof(t_gripd), 0, + A_DEFFLOAT, 0); + gripdRcvr_class = class_new(gensym("gripdRcvr"),0,0,sizeof(t_gripd), + 0, 0); + class_addmethod(gripd_class, (t_method)gripd_connect, + gensym("connect"), 0); + class_addmethod(gripd_class, (t_method)gripd_disconnect, + gensym("disconnect"), 0); + class_addmethod(gripd_class, (t_method)gripd_open, + gensym("open"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_openLocked, + gensym("open_locked"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_setPythonPath, + gensym("set_python_path"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_setPath, + gensym("set_path"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_setSTime, + gensym("poll_send"), A_DEFFLOAT, 0); + class_addmethod(gripd_class, (t_method)gripd_setRTime, + gensym("poll_receive"), A_DEFFLOAT, 0); + class_addmethod(gripd_class, (t_method)gripd_lock, + gensym("lock"), 0); + class_addmethod(gripd_class, (t_method)gripd_unlock, + gensym("unlock"), 0); + class_addmethod(gripd_class, (t_method)gripd_setTitle, + gensym("set_title"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_hide, + gensym("hide"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_show, + gensym("show"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_openpanel, + gensym("openpanel"), A_GIMME, 0); + class_addmethod(gripd_class, (t_method)gripd_savepanel, + gensym("savepanel"), A_GIMME, 0); + class_addbang(gripdRcvr_class, (t_method)gripdR_bang); + class_addfloat(gripdRcvr_class, (t_method)gripdR_float); + class_addsymbol(gripdRcvr_class, (t_method)gripdR_symbol); + class_addanything(gripdRcvr_class, (t_method)gripdR_anything); + class_addlist(gripdRcvr_class, (t_method)gripdR_list); +} + +void *gripd_new(t_floatarg port) +{ + t_gripd *x = (t_gripd *)pd_new(gripd_class); + + if (port == 0) + x->x_port = DEFPORT; + else + x->x_port = (int)port; + x->x_bound = 0; + x->x_connected = 0; +#ifdef NT + x->x_localOpened = (int *)malloc(sizeof(int)); +#else + x->x_childPID = 0; + x->x_localOpened = (int *)shmat(shmget(IPC_PRIVATE,sizeof(int), + IPC_CREAT | SHM_R | SHM_W), 0, + 0); +#endif + *(x->x_localOpened) = 0; + x->x_rdeltime = DEFRDELTIME; + x->x_sdeltime = DEFSDELTIME; + x->x_rclock = clock_new(x, (t_method)gripd_recv); + x->x_sclock = clock_new(x, (t_method)gripd_send); + x->x_connectionClock = clock_new(x, (t_method)gripd_trySocket); + x->x_bindClock = clock_new(x, (t_method)gripd_connect); +#ifdef NT + strcpy(x->x_pythExec, "c:\\program files\\python\\"); + strcpy(x->x_pythFile, "..\\gripd\\"); + x->x_wsockInitByMe = 0; +#else + strcpy(x->x_pythExec, ""); + strcpy(x->x_pythFile, "../gripd/"); +#endif + x->x_rcvrListMaxSize = DEFLISTSIZE; + x->x_rcvrs = (t_gripdRcvr **)calloc(x->x_rcvrListMaxSize, + sizeof(t_gripdRcvr *)); + x->x_rcvrListSize = 0; + x->x_sendBuffer[0] = '\0'; + outlet_new(&x->t_ob, &s_float); + x->x_outlet2 = outlet_new(&x->t_ob, &s_float); + gripd_getApplicationPath(x); + return (void *)x; +} + +void gripd_connect(t_gripd *x) +{ + gripd_openSocket(x); + clock_delay(x->x_rclock, x->x_rdeltime); + clock_delay(x->x_sclock, x->x_sdeltime); +} + +void gripd_openSocket(t_gripd *x) +{ +#ifdef NT + char my_name[DEFSTRSIZE]; + struct sockaddr_in my_addr; + struct sockaddr_in new_addr; + struct hostent *hp; + WSADATA wsaData; + int nSize, temp = 1; + unsigned long on = 1; + + if (!x->x_bound) + { + memset(&my_addr, 0, sizeof(struct sockaddr_in)); + memset(&new_addr, 0, sizeof(struct sockaddr_in)); + gethostname(my_name, sizeof(my_name)); + hp = gethostbyname(my_name); + if (hp == NULL) + { + if (WSAGetLastError() == WSANOTINITIALISED) + { + if (WSAStartup (MAKEWORD(1,1), &wsaData) != 0) + post("GrIPD: Failed to initialize winsock"); + else + { + x->x_wsockInitByMe = 1; + gripd_openSocket(x); + return; + } + } + else + { + post("GrIPD: Gethostname Error %d", WSAGetLastError()); + gripd_disconnect(x); + } + } + my_addr.sin_family = hp->h_addrtype; + my_addr.sin_port = htons(x->x_port); + x->x_sock = socket(AF_INET, SOCK_STREAM, 0); + if (x->x_sock == INVALID_SOCKET) + { + post("GrIPD: Socket Error %d", WSAGetLastError()); + gripd_disconnect(x); + } + else + { + ioctlsocket(x->x_sock, FIONBIO, &on); + setsockopt(x->x_sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&temp, sizeof(temp)); + } + if (bind(x->x_sock, (struct sockaddr *)&my_addr, + sizeof(struct sockaddr)) == SOCKET_ERROR) + { + post("GrIPD: Bind Error %d", WSAGetLastError()); + post("GrIPD: Attempting to re-bind"); + clock_delay(x->x_bindClock, REBINDTIME); + } + else + { + nSize = sizeof(struct sockaddr_in); + getsockname(x->x_sock, (struct sockaddr *)&new_addr, &nSize); + x->x_port = (int)ntohs(new_addr.sin_port); + post("GrIPD: Using port %d", x->x_port); + x->x_bound = 1; + listen(x->x_sock, BACKLOG); + post("GrIPD: Waiting for a connection..."); + clock_delay(x->x_connectionClock, CONNECTIONPOLLTIME); + } + } + else + post("GrIPD: Already waiting for a connection"); +#else + char portstr[MAXPORTSTRLEN]; + struct sockaddr_in my_addr, new_addr; + int nSize, temp = 1; + + if (!x->x_bound) + { + x->x_sock = -1; + if ((x->x_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror("GrIPD: Socket Error"); + gripd_disconnect(x); + } + setsockopt(x->x_sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&temp, sizeof(temp)); + fcntl(x->x_sock, F_SETFL, O_NONBLOCK); + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(x->x_port); + my_addr.sin_addr.s_addr = INADDR_ANY; + bzero(&(my_addr.sin_zero), 8); + if (bind(x->x_sock, (struct sockaddr *)&my_addr, + sizeof(struct sockaddr)) == -1) + { + perror("GrIPD: Bind Error"); + clock_delay(x->x_bindClock, REBINDTIME); + } + else + { + nSize = sizeof(struct sockaddr_in); + getsockname(x->x_sock, (struct sockaddr *)&new_addr, &nSize); + x->x_port = ntohs(new_addr.sin_port); + post("GrIPD: Using port %d", x->x_port); + x->x_bound = 1; + if (listen(x->x_sock, BACKLOG) == -1) + { + perror("GrIPD: Listen Error"); + gripd_disconnect(x); + } + post("GrIPD: Waiting for a connection..."); + clock_delay(x->x_connectionClock, CONNECTIONPOLLTIME); + } + } + else + post("GrIPD: Already waiting for a connection"); +#endif +} + +void gripd_disconnect(t_gripd *x) +{ + int numbytes; + char buf[MAXDATASIZE]; + + clock_unset(x->x_sclock); + clock_unset(x->x_rclock); + clock_unset(x->x_bindClock); + clock_unset(x->x_connectionClock); + if (*(x->x_localOpened)) + { + gripd_closePyth(x); + } + else + { + sprintf(buf, "%s%c0%c", CLOSECOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + numbytes = recv(x->x_newSock, buf, MAXDATASIZE, MSG_NOSIGNAL); + } + if (x->x_bound) + { + gripd_closeSocket(x); + } +} + +void gripd_trySocket(t_gripd *x) +{ +#ifdef NT + fd_set rfds; + struct timeval tv; + unsigned long on; + + on = 1; + tv.tv_sec = 0; + tv.tv_usec = WAITTIME; + FD_ZERO(&rfds); + FD_SET(x->x_sock, &rfds); + if (select(x->x_sock + 1, &rfds, NULL, NULL, &tv) > 0) + { + x->x_newSock = accept(x->x_sock, NULL, NULL); + if (x->x_newSock == INVALID_SOCKET) + { + post("GrIPD: Accept Error %d", WSAGetLastError()); + gripd_disconnect(x); + } + else + { + ioctlsocket(x->x_newSock, FIONBIO, &on); + x->x_connected = 1; + outlet_float(x->t_ob.ob_outlet, 1); + post("GrIPD: Connected"); + } + } + else + clock_delay(x->x_connectionClock, CONNECTIONPOLLTIME); +#else + fd_set rfds; + struct timeval tv; + struct sockaddr_in their_addr; + int new_fd, sin_size; + + sin_size = sizeof(struct sockaddr_in); + tv.tv_sec = 0; + tv.tv_usec = WAITTIME; + FD_ZERO(&rfds); + FD_SET(x->x_sock, &rfds); + if (select(x->x_sock + 1, &rfds, NULL, NULL, &tv)) + { + if ((x->x_newSock = accept(x->x_sock, + (struct sockaddr *)&their_addr, + &sin_size)) == -1) + { + perror("GrIPD: Accept Error"); + gripd_disconnect(x); + } + else + { + x->x_connected = 1; + outlet_float(x->t_ob.ob_outlet, 1); + post("GrIPD: Connected"); + } + } + else + clock_delay(x->x_connectionClock, CONNECTIONPOLLTIME); +#endif +} + +void gripd_closeSocket(t_gripd *x) +{ +#ifdef NT + closesocket(x->x_newSock); + closesocket(x->x_sock); +#else + shutdown(x->x_newSock, 2); + close(x->x_newSock); + shutdown(x->x_sock, 2); + close(x->x_sock); +#endif + x->x_bound = 0; + x->x_connected = 0; + *(x->x_localOpened) = 0; + outlet_float(x->t_ob.ob_outlet, 0); + outlet_float(x->x_outlet2, 0); +} + +void gripd_recv(t_gripd *x) +{ + int numbytes, count, idx, i, j, argc; + char buf[MAXDATASIZE], symName[MAXSYMNAMELEN], + symValue[MAXSYMVALUELEN], + tempString[MAXDATASIZE]; + t_symbol *tempSym; + t_atom atomList[MAXALISTLEN]; + numbytes = count = idx = i = j = argc = 0; + tempSym = gensym(""); + + if (x->x_connected) + { + numbytes = recv(x->x_newSock, buf, MAXDATASIZE, + MSG_DONTWAIT | MSG_NOSIGNAL); + if (numbytes > 0) + { + buf[numbytes] = '\0'; + while (count <= numbytes) + { + while ((buf[count] != SYMMSGSEP) && (count <= numbytes)) + { + symName[i] = buf[count]; + count++; + i++; + } + symName[i] = '\0'; + i = 0; + count++; + while ((buf[count] != PAIRSEPCHAR) && (count <= numbytes)) + { + symValue[i] = buf[count]; + count ++; + i++; + } + symValue[i] = '\0'; + count++; + i = 0; + if (symName[0] == COMMANDCHAR) + { + if ((strcmp(SETRCVRSTRING, symName) == 0) \ + && (gripd_checkExistance(x, symValue) == 0)) + { + if (x->x_rcvrListSize \ + == (x->x_rcvrListMaxSize - 1)) + gripd_expandRcvrList(x); + gripd_makeGripdRcvr(x, gensym(symValue)); + x->x_rcvrListSize++; + } + if (strcmp(CLOSECOMMAND, symName) == 0) + { + post("GrIPD: Connection closed remotely"); + gripd_disconnect(x); + } + if (strcmp(HIDECOMMAND, symName) == 0) + { + outlet_float(x->x_outlet2, 0); + } + if (strcmp(SHOWCOMMAND, symName) == 0) + { + outlet_float(x->x_outlet2, 1); + } + if (strcmp(PINGCOMMAND, symName) == 0) + { + char pingCommandStr[64]; + + sprintf(pingCommandStr, + "%s%c0%c", + PINGCOMMAND, + SYMMSGSEP, + PAIRSEPCHAR); + gripd_appendSendBuffer(x, pingCommandStr); + gripd_send(x); + } + } + else + { + tempSym = gensym(symName); + if (tempSym->s_thing) + { + if (strcmp(BANGSTRING, symValue) == 0) + pd_bang(tempSym->s_thing); + else + { + if (strchr(symValue, ' ') == NULL) + { + if (gripd_isNumeric(symValue)) + pd_float(tempSym->s_thing, + (float)atof(symValue)); + else + typedmess(tempSym->s_thing, + gensym(symValue), + 0, + NULL); + } + else + { + idx = 0; + argc = 0; + for (j = 0; j < (int)strlen(symValue); j++) + { + if (symValue[j] != ' ') + { + tempString[idx] = symValue[j]; + idx++; + } + if ((symValue[j] == ' ') + || (j == (int)strlen(symValue) -1)) + { + tempString[idx] = '\0'; + if (gripd_isNumeric(tempString)) + { + atomList[argc].a_type = A_FLOAT; + atomList[argc].a_w.w_float = + (float)atof(tempString); + } + else + { + atomList[argc].a_type = A_SYMBOL; + atomList[argc].a_w.w_symbol + = gensym(tempString); + } + argc++; + idx = 0; + } + } + if (atomList[0].a_type == A_FLOAT) + pd_list(tempSym->s_thing, + atomList[0].a_w.w_symbol, + argc, atomList); + else + typedmess(tempSym->s_thing, + atomList[0].a_w.w_symbol, + argc - 1, &(atomList[1])); + } + } + } + } + } + } + } + clock_delay(x->x_rclock, x->x_rdeltime); +} + +void gripd_send(t_gripd *x) +{ + int charsSent, endPos; + if (x->x_connected && (strlen(x->x_sendBuffer) > 0)) + { + charsSent = send(x->x_newSock, x->x_sendBuffer, + strlen(x->x_sendBuffer), + MSG_DONTWAIT | MSG_NOSIGNAL); + if (charsSent == SOCKET_ERROR) + { + post("GrIPD: Client is not responding"); + gripd_disconnect(x); + return; + } + else if ((charsSent <= (signed int)strlen(x->x_sendBuffer)) && + (charsSent > -1)) + { + endPos = strlen(x->x_sendBuffer) - charsSent; + strcpy(x->x_sendBuffer, &(x->x_sendBuffer[charsSent])); + x->x_sendBuffer[endPos] = '\0'; + } + } + clock_delay(x->x_sclock, x->x_sdeltime); +} + +/* this does NOT take care of separator strings, sending function must + do that */ +void gripd_appendSendBuffer(t_gripd *x, char *aString) +{ + if (x->x_connected) + { + /* +1 below since strlen does not include '\0' */ + if ((strlen(x->x_sendBuffer) + strlen(aString)) + 1 > MAXDATASIZE) + post("GrIPD: Send buffer overflow"); + else + strcat(x->x_sendBuffer, aString); + } +} + +void gripd_open(t_gripd *x, t_symbol *sym, int argc, t_atom *argv) +{ + gripd_openPyth(x, sym, argc, argv, 0); +} +void gripd_openLocked(t_gripd *x, t_symbol *sym, int argc, t_atom *argv) +{ + gripd_openPyth(x, sym, argc, argv, 1); +} + +void gripd_openPyth(t_gripd *x, t_symbol *sym, int argc, + t_atom *argv, int locked) +{ +#ifdef NT + STARTUPINFO si; + PROCESS_INFORMATION pi; + char pythExec[DEFSTRSIZE], filename[DEFSTRSIZE], tempStr[DEFSTRSIZE]; + int i; + + if (!x->x_connected && !(*(x->x_localOpened))) + { + gripd_connect(x); + *(x->x_localOpened) = 1; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + if (argc > 0) + { + if (argv[0].a_type == A_SYMBOL) + { + strcpy(filename, argv[0].a_w.w_symbol->s_name); + for (i = 1; i < argc; i++) + if (argv[i].a_type == A_SYMBOL) + sprintf(filename, "%s %s", filename, + argv[i].a_w.w_symbol->s_name); + } + else + strcpy(filename, "0"); + } + else + strcpy(filename, "0"); + for (i = 0; i < (int)strlen(x->x_pythExec); i++) + if (x->x_pythExec[i] == '/') + x->x_pythExec[i] = '\\'; + for (i = 0; i < (int)strlen(x->x_pythFile); i++) + if (x->x_pythFile[i] == '/') + x->x_pythFile[i] = '\\'; + for (i = 0; i < (int)strlen(filename); i++) + if (filename[i] == '/') + filename[i] = '\\'; + if (filename[0] == '.' && + (filename[1] == '\\' || + (filename[1] == '.' && filename[2] == '\\'))) + { + sprintf(tempStr, "%s%s", x->x_appPath, filename); + strcpy(filename, tempStr); + } + if (x->x_pythFile[0] == '.' && + (x->x_pythFile[1] == '\\' || + (x->x_pythFile[1] == '.' && x->x_pythFile[2] == '\\'))) + { + sprintf(tempStr, "%s%s", x->x_appPath, x->x_pythFile); + strcpy(x->x_pythFile, tempStr); + } + sprintf(pythExec, "\"%sgripd.exe\" \"%s\" %d 1 %d", x->x_pythFile, + filename, x->x_port, locked); + if (!(CreateProcess(NULL, pythExec, NULL, NULL, FALSE, 0, NULL, NULL, + &si, &(x->x_childProcessInfo)) != 0)) + { + post("GrIPD: Failed to execute %sgripd.exe", x->x_pythFile); + sprintf(pythExec, "\"%spython.exe\" \"%sgripd.py\" \"%s\" %d 1 %d", + x->x_pythExec, x->x_pythFile, filename, x->x_port, locked); + if (!(CreateProcess(NULL, pythExec, NULL, NULL, FALSE, 0, NULL, + NULL, &si, &(x->x_childProcessInfo)) != 0)) + { + post("GrIPD: Failed to execute %spython.exe", x->x_pythExec); + gripd_disconnect(x); + *(x->x_localOpened) = 0; + } + } + } +#else + char pythExec[DEFSTRSIZE], filename[DEFSTRSIZE], portString[DEFSTRSIZE], + lockedString[DEFSTRSIZE], tempStr[DEFSTRSIZE]; + int i, pid; + + if (!x->x_connected && !(*(x->x_localOpened))) + { + gripd_connect(x); + pid = fork(); + if (pid == 0) + { + struct sched_param par; + int p1; + + /* Lose setuid priveliges */ + seteuid(getuid()); + *(x->x_localOpened) = 1; + /* set lowest priority, SCHED_OTHER policy, unlock mem*/ +#ifdef _POSIX_PRIORITY_SCHEDULING + p1 = sched_get_priority_min(SCHED_OTHER); + par.sched_priority = p1; + if (sched_setscheduler(0, SCHED_OTHER, &par) == -1) + post("GrIPD: unable to set priority %d scheduling.", p1); +#endif +#ifdef _POSIX_MEMLOCK + if ((munlockall() == -1) && (!getuid())) + post("GrIPD: unable to unlock memory."); +#endif + clock_free(x->x_rclock); + clock_free(x->x_sclock); + clock_free(x->x_connectionClock); + clock_free(x->x_bindClock); + for (i = 0; i < x->x_rcvrListSize; i++) + pd_unbind(&(x->x_rcvrs[i])->r_obj.ob_pd, + x->x_rcvrs[i]->r_sym); + free(x->x_rcvrs); + sprintf(pythExec, "%sgripd", x->x_pythFile); + if (argc > 0) + { + strcpy(filename, argv[0].a_w.w_symbol->s_name); + for (i = 1; i < argc; i++) + if (argv[i].a_type == A_SYMBOL) + sprintf(filename, "%s %s", filename, + argv[i].a_w.w_symbol->s_name); + } + else + strcpy(filename, "0"); + if (filename[0] == '.' && + (filename[1] == '/' || + (filename[1] == '.' && filename[2] == '/'))) + { + sprintf(tempStr, "%s%s", x->x_appPath, filename); + strcpy(filename, tempStr); + } + if (pythExec[0] == '.' && + (pythExec[1] == '/' || + (pythExec[1] == '.' && pythExec[2] == '/'))) + { + sprintf(tempStr, "%s%s", x->x_appPath, pythExec); + strcpy(pythExec, tempStr); + } + /* set x_localOpened before opened since execlp will exit + process on success */ + sprintf(portString, "%d", x->x_port); + sprintf(lockedString, "%d", locked); + if ((execlp(pythExec, pythExec, filename, portString, + "1", lockedString, (char *)0)) == -1) + { + post("GrIPD: Error launching %s", pythExec); + perror(" "); + *(x->x_localOpened) = 0; + exit(1); + } + exit(1); + } + else + { + x->x_childPID = pid; + } + } +#endif + else + { + gripd_show(x); + } +} + +void gripd_closePyth(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (*(x->x_localOpened)) + { + sprintf(buf, "%s%c0%c", CLOSECOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + *(x->x_localOpened) = 0; +#ifdef NT + TerminateProcess(x->x_childProcessInfo.hProcess, 0); +#else + kill(x->x_childPID, SIGKILL); + x->x_childPID = 0; +#endif + } +} + +void gripd_lock(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (x->x_connected) + { + sprintf(buf, "%s%c0%c", LOCKCOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_unlock(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (x->x_connected) + { + sprintf(buf, "%s%c0%c", UNLOCKCOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_hide(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (x->x_connected) + { + sprintf(buf, "%s%c0%c", HIDECOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_show(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (x->x_connected) + { + sprintf(buf, "%s%c0%c", SHOWCOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_openpanel(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (x->x_connected) + { + sprintf(buf, "%s%c0%c", OPENPANELCOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_savepanel(t_gripd *x) +{ + char buf[MAXDATASIZE]; + + if (x->x_connected) + { + sprintf(buf, "%s%c0%c", SAVEPANELCOMMAND, SYMMSGSEP, PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_setTitle(t_gripd *x, t_symbol *sym, int argc, t_atom *argv) +{ + int i; + char title[DEFSTRSIZE]; + char buf[MAXDATASIZE]; + + if (x->x_connected) { + if (argc > 0) + strcpy(title, argv[0].a_w.w_symbol->s_name); + for (i = 1; i < argc; i++) + if (argv[i].a_type == A_SYMBOL) + sprintf(title, "%s %s", title, + argv[i].a_w.w_symbol->s_name); + sprintf(buf, + "%s%c%s%c", + SETTITLECOMMAND, + SYMMSGSEP, + title, + PAIRSEPCHAR); + send(x->x_newSock, buf, strlen(buf), MSG_DONTWAIT | MSG_NOSIGNAL); + } +} + +void gripd_setPath(t_gripd *x, t_symbol *sym, int argc, t_atom *argv) +{ + int i; + if (argc > 0) + strcpy(x->x_pythFile, argv[0].a_w.w_symbol->s_name); + for (i = 1; i < argc; i++) + if (argv[i].a_type == A_SYMBOL) + sprintf(x->x_pythFile, "%s %s", x->x_pythFile, + argv[i].a_w.w_symbol->s_name); + sprintf(x->x_pythFile, "%s/", x->x_pythFile); +} + +void gripd_setPythonPath(t_gripd *x, t_symbol *sym, int argc, t_atom *argv) +{ + int i; + if (argc >0) + strcpy(x->x_pythExec, argv[0].a_w.w_symbol->s_name); + for (i = 1; i < argc; i++) + if (argv[i].a_type == A_SYMBOL) + sprintf(x->x_pythExec, "%s %s", x->x_pythExec, + argv[i].a_w.w_symbol->s_name); + sprintf(x->x_pythExec, "%s/", x->x_pythExec); +} + +void gripd_setSTime(t_gripd *x, t_floatarg val) +{ + if (val > 0) + x->x_sdeltime = val; + else + post("GrIPD: Illegal update time"); +} + +void gripd_setRTime(t_gripd *x, t_floatarg val) +{ + if (val > 0) + x->x_rdeltime = val; + else + post("GrIPD: Illegal update time"); +} + +void gripdR_bang(t_gripdRcvr *r) +{ + char aString[MAXDATASIZE]; + char valueString[MAXDATASIZE]; + + strcpy(aString, r->r_sym->s_name); + sprintf(valueString,"%cbang%c", SYMMSGSEP, PAIRSEPCHAR); + strcat(aString, valueString); + + gripd_appendSendBuffer((t_gripd *)(r->r_x), aString); +} + +void gripdR_float(t_gripdRcvr *r, t_float floatValue) +{ + char aString[MAXDATASIZE]; + char valueString[MAXDATASIZE]; + + strcpy(aString, r->r_sym->s_name); + sprintf(valueString,"%c%g%c", SYMMSGSEP, floatValue, PAIRSEPCHAR); + strcat(aString, valueString); + + gripd_appendSendBuffer((t_gripd *)(r->r_x), aString); +} + +void gripdR_symbol(t_gripdRcvr *r, t_symbol *sym) +{ + char aString[MAXDATASIZE]; + char valueString[MAXDATASIZE]; + + strcpy(aString, r->r_sym->s_name); + sprintf(valueString,"%c%s%c", SYMMSGSEP, sym->s_name, PAIRSEPCHAR); + strcat(aString, valueString); + + gripd_appendSendBuffer((t_gripd *)(r->r_x), aString); +} + +void gripdR_anything(t_gripdRcvr *r, t_symbol *sym, int argc, t_atom *argv) +{ + char aString[MAXDATASIZE]; + char valueString[MAXDATASIZE]; + int i; + + strcpy(aString, r->r_sym->s_name); + sprintf(valueString, "%c%s", SYMMSGSEP, sym->s_name); + strcat(aString, valueString); + for (i = 0; i < argc; i++) + { + if (argv[i].a_type == A_SYMBOL) + { + sprintf(valueString, " %s", argv[i].a_w.w_symbol->s_name); + strcat(aString, valueString); + } + else if (argv[i].a_type == A_FLOAT) + { + sprintf(valueString, " %g", argv[i].a_w.w_float); + strcat(aString, valueString); + } + } + sprintf(aString, "%s%c", aString, PAIRSEPCHAR); + gripd_appendSendBuffer((t_gripd *)(r->r_x), aString); +} + +void gripdR_list(t_gripdRcvr *r, t_symbol *sym, int argc, t_atom *argv) +{ + char aString[MAXDATASIZE]; + char valueString[MAXDATASIZE]; + int i; + + strcpy(aString, r->r_sym->s_name); + sprintf(valueString, "%c", SYMMSGSEP); + strcat(aString, valueString); + for (i = 0; i < argc; i++) + { + if (argv[i].a_type == A_SYMBOL) + { + sprintf(valueString, " %s", argv[i].a_w.w_symbol->s_name); + strcat(aString, valueString); + } + else if (argv[i].a_type == A_FLOAT) + { + sprintf(valueString, " %g", argv[i].a_w.w_float); + strcat(aString, valueString); + } + } + sprintf(aString, "%s%c", aString, PAIRSEPCHAR); + gripd_appendSendBuffer((t_gripd *)(r->r_x), aString); +} + +void gripd_makeGripdRcvr(t_gripd *x, t_symbol *s) +{ + t_gripdRcvr *r = (t_gripdRcvr *)pd_new(gripdRcvr_class); + r->r_sym = s; + pd_bind(&r->r_obj.ob_pd, s); + r->r_x = (t_gripd *)x; + x->x_rcvrs[x->x_rcvrListSize] = r; +} + +int gripd_checkExistance(t_gripd *x, char *name) +{ + int i, flag; + + flag = 0; + for (i = 0; i < x->x_rcvrListSize; i++) + { + if (strcmp(name, x->x_rcvrs[i]->r_sym->s_name) == 0) + flag = 1; + } + return flag; +} + +void gripd_expandRcvrList(t_gripd *x) +{ + x->x_rcvrListMaxSize *= 2; + x->x_rcvrs = (t_gripdRcvr **)realloc(x->x_rcvrs, + x->x_rcvrListMaxSize \ + * sizeof(t_gripdRcvr *)); +} + +void gripd_free(t_gripd *x) +{ + int i; + + if (*(x->x_localOpened)) + gripd_closePyth(x); + if (x->x_connected) + gripd_disconnect(x); + else if (x->x_bound) + gripd_closeSocket(x); + clock_free(x->x_rclock); + clock_free(x->x_sclock); + clock_free(x->x_connectionClock); + clock_free(x->x_bindClock); +#ifdef NT + free(x->x_localOpened); + if (x->x_wsockInitByMe != 0) + WSACleanup(); +#endif + for (i = 0; i < x->x_rcvrListSize; i++) + pd_unbind(&(x->x_rcvrs[i])->r_obj.ob_pd, x->x_rcvrs[i]->r_sym); + free(x->x_rcvrs); +} + +int gripd_isNumeric(char *string) +{ + if ((strspn(string, "0123456789.+-") == strlen(string)) && + (strchr(string, '+') == strrchr(string, '+')) && + (strchr(string, '-') == strrchr(string, '-')) && + (strchr(string, '.') == strrchr(string, '.')) && + (!((strchr(string, '+') != NULL) && + (strchr(string, '-') != NULL)))) + return 1; + else + return 0; +} + +#ifndef NT +void gripd_sigChild(int sig) +{ + wait(NULL); +} +#endif + +void gripd_getApplicationPath(t_gripd *x) +{ + char rawStr[MAXDATASIZE]; +#ifdef NT + GetModuleFileName(NULL, rawStr, sizeof(rawStr)); + rawStr[strrchr(rawStr, '\\') - rawStr + 1] = '\0'; + strcpy(x->x_appPath, rawStr); +#else + char *pathStr; + FILE *fp; + fp = fopen("/proc/self/maps", "r"); + fgets(rawStr, MAXDATASIZE, fp); + fclose(fp); + pathStr = index(rawStr, '/'); + pathStr[index(pathStr, '\n') - pathStr] = '\0'; + pathStr[rindex(pathStr, '/') - pathStr + 1] = '\0'; + strcpy(x->x_appPath, pathStr); +#endif +} + diff --git a/src/gripd.h b/src/gripd.h new file mode 100644 index 0000000..67ef16b --- /dev/null +++ b/src/gripd.h @@ -0,0 +1,227 @@ +/* GrIPD v0.1.1 - Graphical Interface for Pure Data +** Copyright (C) 2003 Joseph A. Sarlo +** +** This program is free software; you can redistribute it and/orsig +** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** jsarlo@ucsd.edu +*/ + +#include "m_pd.h" +#include +#include +#include +#include +#include +#ifdef NT +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#define VERSION "0.1.1" +#define DEFPORT 0 +/* maxiumum connections */ +#define BACKLOG 1 +/* max size of send buffer */ +#define MAXDATASIZE 16384 +#define MAXPORTSTRLEN 16 +#define MAXSYMNAMELEN 128 +#define MAXSYMVALUELEN 128 +/* separates send/recv object names from value they send/recv */ +#define SYMMSGSEP 31 +/* separates send/recv value pairs */ +#define PAIRSEPCHAR 29 +#define BANGSTRING "bang" +/* if 1st char, indicates send/recv name is actually a command */ +#define COMMANDCHAR '!' +/* command to add value to recv list */ +#define SETRCVRSTRING "!setRcvr" +/* command to close connection */ +#define CLOSECOMMAND "!disconnect" +/* command to close python app */ +#define EXITCOMMAND "!exit" +/* command to lock GUI */ +#define LOCKCOMMAND "!lock" +/* command to unlock GUI */ +#define UNLOCKCOMMAND "!unlock" +/* command to set title */ +#define SETTITLECOMMAND "!settitle" +/* command to hide GUI window */ +#define HIDECOMMAND "!hide" +/* command to show GUI window */ +#define SHOWCOMMAND "!show" +/* command for connection status */ +#define PINGCOMMAND "!ping" +// command to have GUI open a open file dialog +#define OPENPANELCOMMAND "!openpanel" +// command to have GUI open a save file dialog +#define SAVEPANELCOMMAND "!savepanel" +/* initial size of rcvr object list */ +#define DEFLISTSIZE 16 +/* poll time in ms to re-try accept() */ +#define CONNECTIONPOLLTIME 100 +/* blocking time us for accept() */ +#define WAITTIME 1 +/* poll time in ms to re-try bind after "address already in use" */ +#define REBINDTIME 1000 +/* default receive poll time in ms */ +#define DEFRDELTIME 5 +#define DEFSDELTIME 1 +/* default send poll time in ms */ +#define DEFSTRSIZE 256 +#define MAXALISTLEN 64 + +#ifdef NT +#define MSG_DONTWAIT 0 +#define MSG_NOSIGNAL 0 +#define MSG_WAITALL 0 +#else +#define SOCKET_ERROR -1 +#endif + +/* Individual "receive" class */ +typedef struct _gripdRcvr +{ + t_object r_obj; + t_symbol *r_sym; + /* gripd object, needed so recevied symbol functions can access + gripd data (socket)*/ + void *r_x; +}t_gripdRcvr; + +/* Main object class */ +typedef struct _gripd +{ + t_object t_ob; + t_outlet *x_outlet2; + unsigned short int x_port; +#ifdef NT + SOCKET x_sock; + SOCKET x_newSock; + /* for Windows, 1 if WSAStartup is called */ + int x_wsockInitByMe; + PROCESS_INFORMATION x_childProcessInfo; +#else + int x_sock; + int x_newSock; + int x_childPID; +#endif + /* 1 if socket has been bound, 0 otherwise */ + int x_bound; + /* 1 if currently connected, 0 otherwise */ + int x_connected; + /* 1 if PD opened python app, otherwise (shared mem for linux)*/ + int *x_localOpened; + /* timer for receiveing/sending */ + t_clock *x_rclock; + t_clock *x_sclock; + /* timer for polling accept() */ + t_clock *x_connectionClock; + /* timer for re-binding after "address already in use" error */ + t_clock *x_bindClock; + /* path to python.exe for Windows */ + char x_pythExec[DEFSTRSIZE]; + /* path to gripd.py (or gripd.exe and gripd.py in Windows) */ + char x_pythFile[DEFSTRSIZE]; + /* send/receive poll times */ + double x_sdeltime; + double x_rdeltime; + /* current number of receive "objects" being used */ + int x_rcvrListSize; + /* size currently allocated for receiver objects */ + int x_rcvrListMaxSize; + /* pointer to list of receiver objects */ + t_gripdRcvr **x_rcvrs; + /* buffer to be sent */ + char x_sendBuffer[MAXDATASIZE]; + /* path to application */ + char x_appPath[MAXDATASIZE]; +}t_gripd; + +t_class *gripd_class; +t_class *gripdRcvr_class; + +void gripd_setup(void); +void *gripd_new(t_floatarg port); +void gripd_connect(t_gripd *x); +/* initialize "server" */ +void gripd_openSocket(t_gripd *x); +/* shutdown server */ +void gripd_disconnect(t_gripd *x); +/* poll accept() */ +void gripd_trySocket(t_gripd *x); +void gripd_closeSocket(t_gripd *x); +void gripd_recv(t_gripd *x); +void gripd_send(t_gripd *x); +/* add name:value pair to send string */ +void gripd_appendSendBuffer(t_gripd *x, char *aString); +/* open gripd.py (or gripd.exe inWindows) unlocked mode*/ +void gripd_open(t_gripd *x, t_symbol *sym, int argc, t_atom *argv); +/* open gripd.py (or gripd.exe inWindows) locked mode*/ +void gripd_openLocked(t_gripd *x, t_symbol *sym, int argc, t_atom *argv); +/* actually open gripd.py (or gripd.exe inWindows)*/ +void gripd_openPyth(t_gripd *x, t_symbol *sym, int argc, + t_atom *argv, int locked); +/* tell python app to close itself */ +void gripd_closePyth(t_gripd *x); +/* lock GUI */ +void gripd_lock(t_gripd *x); +/* unlock GUI */ +void gripd_unlock(t_gripd *x); +/* hide GUI */ +void gripd_hide(t_gripd *x); +/* show GUI */ +void gripd_show(t_gripd *x); +/* set GUI window title */ +void gripd_setTitle(t_gripd *x, t_symbol *sym, int argc, t_atom *argv); +/* set path to gripd.py (or gripd.exe in Windows) */ +void gripd_setPath(t_gripd *x, t_symbol *sym, int argc, t_atom *argv); +/* set path to python.exe for Windows */ +void gripd_setPythonPath(t_gripd *x, t_symbol *sym, int argc, + t_atom *argv); +void gripd_setSTime(t_gripd *x, t_floatarg val); +void gripd_setRTime(t_gripd *x, t_floatarg val); +void gripd_openpanel(t_gripd *x); +void gripd_savepanel(t_gripd *x); +void gripdR_bang(t_gripdRcvr *r); +void gripdR_float(t_gripdRcvr *r, t_float floatValue); +void gripdR_symbol(t_gripdRcvr *r, t_symbol *sym); +void gripdR_anything(t_gripdRcvr *r, t_symbol *sym, int argc, + t_atom *argv); +void gripdR_list(t_gripdRcvr *r, t_symbol *sym, int argc, t_atom *argv); +/* instantiate new rcv object */ +void gripd_makeGripdRcvr(t_gripd *x, t_symbol *s); +/* check is rcv object has already been created */ +int gripd_checkExistance(t_gripd *x, char *name); +/* allocate more mem for recv objects */ +void gripd_expandRcvrList(t_gripd *x); +void gripd_free(t_gripd *x); +int gripd_isNumeric(char *string); +#ifndef NT +void gripd_sigChild(int signum); +#endif +void gripd_getApplicationPath(t_gripd *x); diff --git a/src/joystick.c b/src/joystick.c new file mode 100644 index 0000000..02fddb7 --- /dev/null +++ b/src/joystick.c @@ -0,0 +1,296 @@ +/* GrIPD v0.1.1 - Graphical Interface for Pure Data +** Copyright (C) 2002 Joseph A. Sarlo +** +** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** jsarlo@ucsd.edu +*/ + +#include +#define MAXEVENTS 4096 +#define MAXDEVS 16 +#ifdef NT +#include +#include +#include +#include +#define MAX_AXIS_OUTS 10 +#define MAX_BUTTON_OUTS 32 +#else +#include +#include +#include +#include +#include +#include +#define JOYSTICK_DEVICE "/dev/js0" +#define JS_EVENT_BUTTON 0x01 +#define JS_EVENT_AXIS 0x02 +#define JS_EVENT_INTI 0x80 +#define DEFSCALE 1 +#define DEFTRANSLATION 0 +#define JSIOCGAXES _IOR('j', 0x11, unsigned char) +#define JSIOCGBUTTONS _IOR('j', 0x12, unsigned char) +#define MAXAXES 4 +#endif + +static int eventValue[MAXEVENTS][MAXDEVS]; +static int eventNumber[MAXEVENTS][MAXDEVS]; +static int eventType[MAXEVENTS][MAXDEVS]; +static int eventCount[MAXDEVS]; +static int devCount = 0; +static int devList[MAXDEVS]; +#ifdef NT +static JOYINFOEX joyInfoEx[MAXDEVS]; +static int joyDevNum[MAXDEVS]; +static int joy_buttons[MAXDEVS]; +static int joy_axes[MAXDEVS]; +static int button_val[MAX_BUTTON_OUTS][MAXDEVS]; +static int axis_val[MAX_AXIS_OUTS][MAXDEVS]; +/* FIXME */ +static DWORD *axes_ptr[MAX_AXIS_OUTS][MAXDEVS]; +#else +static int joy_fd[MAXDEVS]; +struct js_event +{ + unsigned int time; + signed short value; + unsigned char type; + unsigned char number; +}; +static struct js_event joy_e[MAXDEVS]; +#endif + +#ifdef NT +extern "C" { +#endif + +int closeDevice(int devno) +{ + if (devList[devno]) + { + devCount--; + devList[devno] = 0; +#ifdef NT + return (1); +#else + if (close(joy_fd[devno]) < 0) + return (0); + else + { + joy_fd[devno] = -1; + return(1); + } +#endif + } +} + +int openDevice(char *dev) +{ +#ifdef NT + int i, num_axes, num_buttons, devId; + JOYCAPS jscaps; + MMRESULT errCode; + if (devCount == 0) + { + for (i = 0; i < MAXDEVS; i++) + { + devList[i] = 0; + } + } + for (i = 0; i < MAXDEVS; i++) + { + if (devList[i] == 0) + { + devId = i; + i = MAXDEVS; + } + } + joyInfoEx[devId].dwSize = sizeof(joyInfoEx); + joyInfoEx[devId].dwFlags = JOY_RETURNALL; + joyDevNum[devId] = (JOYSTICKID1 - 1) + atoi(dev); + errCode = joyGetPosEx(joyDevNum[devId], &joyInfoEx[devId]); + if ((errCode == MMSYSERR_NOERROR) && (devCount < MAXDEVS)) + { + joyGetDevCaps(joyDevNum[devId], &jscaps, sizeof(jscaps)); + if (jscaps.wNumAxes > MAX_AXIS_OUTS) + joy_axes[devId] = MAX_AXIS_OUTS; + else + joy_axes[devId] = jscaps.wNumAxes; + if (jscaps.wNumButtons > MAX_BUTTON_OUTS) + joy_buttons[devId] = MAX_BUTTON_OUTS; + else + joy_buttons[devId] = jscaps.wNumButtons; + for (i = 0; i < joy_axes[devId]; i++) + axis_val[i][devId] = 0; + for (i = 0; i < joy_buttons[devId]; i++) + button_val[i][devId] = 0; + axes_ptr[0][devId] = &(joyInfoEx[devId].dwXpos); + axes_ptr[1][devId] = &(joyInfoEx[devId].dwYpos); + axes_ptr[2][devId] = &(joyInfoEx[devId].dwZpos); + axes_ptr[3][devId] = &(joyInfoEx[devId].dwRpos); + axes_ptr[4][devId] = &(joyInfoEx[devId].dwUpos); + axes_ptr[5][devId] = &(joyInfoEx[devId].dwVpos); + eventCount[devId] = 0; + devCount++; + devList[devId] = 1; + return (devId); + } + else + return (-1); +#else + int i, devId; + char joy_dev[256]; + + if (devCount == 0) + { + for (i = 0; i < MAXDEVS; i++) + { + devList[i] = 0; + } + } + for (i = 0; i < MAXDEVS; i++) + { + if (devList[i] == 0) + { + devId = i; + i = MAXDEVS; + } + } + if (strcmp(dev, "") == 0) + strcpy(joy_dev, JOYSTICK_DEVICE); + else + strcpy(joy_dev, dev); + joy_fd[devId] = open (joy_dev, O_RDONLY | O_NONBLOCK); + if ((joy_fd[devId] == -1) || (devCount >= MAXDEVS)) + { + return (-1); + } + else + { + devCount++; + eventCount[devId] = 0; + devList[devId] = 1; + return (devId); + } +#endif +} + +int readEvents(int devno) +{ +#ifdef NT + int i; + + eventCount[devno] = 0; + joyGetPosEx(joyDevNum[devno], &(joyInfoEx[devno])); + for (i = 0; i < joy_axes[devno]; i++) + if (((int)(*(axes_ptr[i][devno])) != axis_val[i][devno]) && + (eventCount[devno] < MAXEVENTS)) + { + eventType[eventCount[devno]][devno] = 0; + eventNumber[eventCount[devno]][devno] = i; + eventValue[eventCount[devno]][devno] = (int)(*(axes_ptr[i][devno])); + eventCount[devno]++; + axis_val[i][devno] = (int)(*(axes_ptr[i][devno])); + } + for (i = 0; i < joy_buttons[devno]; i ++) + { + if (joyInfoEx[devno].dwButtons & (1 << i)) + { + if ((button_val[i][devno] == 0) && (eventCount[devno] < MAXEVENTS)) + { + eventType[eventCount[devno]][devno] = 1; + eventNumber[eventCount[devno]][devno] = i; + eventValue[eventCount[devno]][devno] = 1; + eventCount[devno]++; + button_val[i][devno] = 1; + } + } + else + if ((button_val[i][devno] == 1) && (eventCount[devno] < MAXEVENTS)) + { + eventType[eventCount[devno]][devno] = 1; + eventNumber[eventCount[devno]][devno] = i; + eventValue[eventCount[devno]][devno] = 0; + eventCount[devno]++; + button_val[i][devno] = 0; + } + } + return (eventCount[devno]); +#else + int i; + + eventCount[devno] = 0; + if (joy_fd[devno] > -1) + { + while (read (joy_fd[devno], &(joy_e[devno]), sizeof(struct js_event)) > -1) + { + if (eventCount[devno] < MAXEVENTS) + { + if (joy_e[devno].type == JS_EVENT_AXIS) + eventType[eventCount[devno]][devno] = 0; + if (joy_e[devno].type == JS_EVENT_BUTTON) + eventType[eventCount[devno]][devno] = 1; + eventNumber[eventCount[devno]][devno] = joy_e[devno].number; + eventValue[eventCount[devno]][devno] = joy_e[devno].value; + eventCount[devno]++; + } + } + } + return eventCount[devno]; +#endif +} + +int getEventCount(int devno) +{ + return (eventCount[devno]); +} + +int getEventType(int devno, int eNum) +{ + int returnVal = 0; + + if (eNum >= 0 && eNum < eventCount[devno]) + { + returnVal = eventType[eNum][devno]; + } + return (returnVal); +} + +int getEventNumber(int devno, int eNum) +{ + int returnVal = 0; + + if (eNum >= 0 && eNum < eventCount[devno]) + { + returnVal = eventNumber[eNum][devno]; + } + return (returnVal); +} + +int getEventValue(int devno, int eNum) +{ + int returnVal = 0; + + if (eNum >= 0 && eNum < eventCount[devno]) + { + returnVal = eventValue[eNum][devno]; + } + return (returnVal); +} +#ifdef NT +} +#endif + diff --git a/src/joystick_wrap.c b/src/joystick_wrap.c new file mode 100644 index 0000000..b2e2087 --- /dev/null +++ b/src/joystick_wrap.c @@ -0,0 +1,692 @@ +/* + * FILE : joystick_wrap.c + * + * This file was automatically generated by : + * Simplified Wrapper and Interface Generator (SWIG) + * Version 1.1 (Patch 5) + * + * Portions Copyright (c) 1995-1998 + * The University of Utah and The Regents of the University of California. + * Permission is granted to distribute this file in any manner provided + * this notice remains intact. + * + * Do not make changes to this file--changes will be lost! + * + */ + + +#define SWIGCODE +/* Implementation : PYTHON */ + +#define SWIGPYTHON +#include +#include +/*********************************************************************** + * $Header: /home/zmoelnig/cvs2svn/pure-data/puredata_cvsbackup/extensions/gripd/src/joystick_wrap.c,v 1.1.1.1 2005-11-10 05:52:09 eighthave Exp $ + * swig_lib/python/python.cfg + * + * This file contains coded needed to add variable linking to the + * Python interpreter. C variables are added as a new kind of Python + * datatype. + * + * Also contains supporting code for building python under Windows + * and things like that. + * + * $Log: not supported by cvs2svn $ + ************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif +#include "Python.h" +#ifdef __cplusplus +} +#endif + +/* Definitions for Windows/Unix exporting */ +#if defined(__WIN32__) +# if defined(_MSC_VER) +# define SWIGEXPORT(a,b) __declspec(dllexport) a b +# else +# if defined(__BORLANDC__) +# define SWIGEXPORT(a,b) a _export b +# else +# define SWIGEXPORT(a,b) a b +# endif +# endif +#else +# define SWIGEXPORT(a,b) a b +#endif + +#ifdef SWIG_GLOBAL +#ifdef __cplusplus +#define SWIGSTATIC extern "C" +#else +#define SWIGSTATIC +#endif +#endif + +#ifndef SWIGSTATIC +#define SWIGSTATIC static +#endif + +typedef struct { + char *name; + PyObject *(*get_attr)(void); + int (*set_attr)(PyObject *); +} swig_globalvar; + +typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar **vars; + int nvars; + int maxvars; +} swig_varlinkobject; + +/* ---------------------------------------------------------------------- + swig_varlink_repr() + + Function for python repr method + ---------------------------------------------------------------------- */ + +static PyObject * +swig_varlink_repr(swig_varlinkobject *v) +{ + v = v; + return PyString_FromString(""); +} + +/* --------------------------------------------------------------------- + swig_varlink_print() + + Print out all of the global variable names + --------------------------------------------------------------------- */ + +static int +swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags) +{ + + int i = 0; + flags = flags; + fprintf(fp,"Global variables { "); + while (v->vars[i]) { + fprintf(fp,"%s", v->vars[i]->name); + i++; + if (v->vars[i]) fprintf(fp,", "); + } + fprintf(fp," }\n"); + return 0; +} + +/* -------------------------------------------------------------------- + swig_varlink_getattr + + This function gets the value of a variable and returns it as a + PyObject. In our case, we'll be looking at the datatype and + converting into a number or string + -------------------------------------------------------------------- */ + +static PyObject * +swig_varlink_getattr(swig_varlinkobject *v, char *n) +{ + int i = 0; + char temp[128]; + + while (v->vars[i]) { + if (strcmp(v->vars[i]->name,n) == 0) { + return (*v->vars[i]->get_attr)(); + } + i++; + } + sprintf(temp,"C global variable %s not found.", n); + PyErr_SetString(PyExc_NameError,temp); + return NULL; +} + +/* ------------------------------------------------------------------- + swig_varlink_setattr() + + This function sets the value of a variable. + ------------------------------------------------------------------- */ + +static int +swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) +{ + char temp[128]; + int i = 0; + while (v->vars[i]) { + if (strcmp(v->vars[i]->name,n) == 0) { + return (*v->vars[i]->set_attr)(p); + } + i++; + } + sprintf(temp,"C global variable %s not found.", n); + PyErr_SetString(PyExc_NameError,temp); + return 1; +} + +statichere PyTypeObject varlinktype = { +/* PyObject_HEAD_INIT(&PyType_Type) Note : This doesn't work on some machines */ + PyObject_HEAD_INIT(0) + 0, + "varlink", /* Type name */ + sizeof(swig_varlinkobject), /* Basic size */ + 0, /* Itemsize */ + 0, /* Deallocator */ + (printfunc) swig_varlink_print, /* Print */ + (getattrfunc) swig_varlink_getattr, /* get attr */ + (setattrfunc) swig_varlink_setattr, /* Set attr */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_mapping*/ + 0, /* tp_hash */ +}; + +/* Create a variable linking object for use later */ + +SWIGSTATIC PyObject * +SWIG_newvarlink(void) +{ + swig_varlinkobject *result = 0; + result = PyMem_NEW(swig_varlinkobject,1); + varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */ + result->ob_type = &varlinktype; + /* _Py_NewReference(result); Does not seem to be necessary */ + result->nvars = 0; + result->maxvars = 64; + result->vars = (swig_globalvar **) malloc(64*sizeof(swig_globalvar *)); + result->vars[0] = 0; + result->ob_refcnt = 0; + Py_XINCREF((PyObject *) result); + return ((PyObject*) result); +} + +SWIGSTATIC void +SWIG_addvarlink(PyObject *p, char *name, + PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) +{ + swig_varlinkobject *v; + v= (swig_varlinkobject *) p; + + if (v->nvars >= v->maxvars -1) { + v->maxvars = 2*v->maxvars; + v->vars = (swig_globalvar **) realloc(v->vars,v->maxvars*sizeof(swig_globalvar *)); + if (v->vars == NULL) { + fprintf(stderr,"SWIG : Fatal error in initializing Python module.\n"); + exit(1); + } + } + v->vars[v->nvars] = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + v->vars[v->nvars]->name = (char *) malloc(strlen(name)+1); + strcpy(v->vars[v->nvars]->name,name); + v->vars[v->nvars]->get_attr = get_attr; + v->vars[v->nvars]->set_attr = set_attr; + v->nvars++; + v->vars[v->nvars] = 0; +} + + + +/***************************************************************************** + * $Header: /home/zmoelnig/cvs2svn/pure-data/puredata_cvsbackup/extensions/gripd/src/joystick_wrap.c,v 1.1.1.1 2005-11-10 05:52:09 eighthave Exp $ + * + * swigptr.swg + * + * This file contains supporting code for the SWIG run-time type checking + * mechanism. The following functions are available : + * + * SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)); + * + * Registers a new type-mapping with the type-checker. origtype is the + * original datatype and newtype is an equivalent type. cast is optional + * pointer to a function to cast pointer values between types (this + * is typically used to cast pointers from derived classes to base classes in C++) + * + * SWIG_MakePtr(char *buffer, void *ptr, char *typestring); + * + * Makes a pointer string from a pointer and typestring. The result is returned + * in buffer which is assumed to hold enough space for the result. + * + * char * SWIG_GetPtr(char *buffer, void **ptr, char *type) + * + * Gets a pointer value from a string. If there is a type-mismatch, returns + * a character string to the received type. On success, returns NULL. + * + * + * You can remap these functions by making a file called "swigptr.swg" in + * your the same directory as the interface file you are wrapping. + * + * These functions are normally declared static, but this file can be + * can be used in a multi-module environment by redefining the symbol + * SWIGSTATIC. + *****************************************************************************/ + +#include + +#ifdef SWIG_GLOBAL +#ifdef __cplusplus +#define SWIGSTATIC extern "C" +#else +#define SWIGSTATIC +#endif +#endif + +#ifndef SWIGSTATIC +#define SWIGSTATIC static +#endif + + +/* SWIG pointer structure */ + +typedef struct SwigPtrType { + char *name; /* Datatype name */ + int len; /* Length (used for optimization) */ + void *(*cast)(void *); /* Pointer casting function */ + struct SwigPtrType *next; /* Linked list pointer */ +} SwigPtrType; + +/* Pointer cache structure */ + +typedef struct { + int stat; /* Status (valid) bit */ + SwigPtrType *tp; /* Pointer to type structure */ + char name[256]; /* Given datatype name */ + char mapped[256]; /* Equivalent name */ +} SwigCacheType; + +/* Some variables */ + +static int SwigPtrMax = 64; /* Max entries that can be currently held */ + /* This value may be adjusted dynamically */ +static int SwigPtrN = 0; /* Current number of entries */ +static int SwigPtrSort = 0; /* Status flag indicating sort */ +static int SwigStart[256]; /* Starting positions of types */ + +/* Pointer table */ +static SwigPtrType *SwigPtrTable = 0; /* Table containing pointer equivalences */ + +/* Cached values */ + +#define SWIG_CACHESIZE 8 +#define SWIG_CACHEMASK 0x7 +static SwigCacheType SwigCache[SWIG_CACHESIZE]; +static int SwigCacheIndex = 0; +static int SwigLastCache = 0; + +/* Sort comparison function */ +static int swigsort(const void *data1, const void *data2) { + SwigPtrType *d1 = (SwigPtrType *) data1; + SwigPtrType *d2 = (SwigPtrType *) data2; + return strcmp(d1->name,d2->name); +} + +/* Binary Search function */ +static int swigcmp(const void *key, const void *data) { + char *k = (char *) key; + SwigPtrType *d = (SwigPtrType *) data; + return strncmp(k,d->name,d->len); +} + +/* Register a new datatype with the type-checker */ + +SWIGSTATIC +void SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)) { + + int i; + SwigPtrType *t = 0,*t1; + + /* Allocate the pointer table if necessary */ + + if (!SwigPtrTable) { + SwigPtrTable = (SwigPtrType *) malloc(SwigPtrMax*sizeof(SwigPtrType)); + SwigPtrN = 0; + } + /* Grow the table */ + if (SwigPtrN >= SwigPtrMax) { + SwigPtrMax = 2*SwigPtrMax; + SwigPtrTable = (SwigPtrType *) realloc((char *) SwigPtrTable,SwigPtrMax*sizeof(SwigPtrType)); + } + for (i = 0; i < SwigPtrN; i++) + if (strcmp(SwigPtrTable[i].name,origtype) == 0) { + t = &SwigPtrTable[i]; + break; + } + if (!t) { + t = &SwigPtrTable[SwigPtrN]; + t->name = origtype; + t->len = strlen(t->name); + t->cast = 0; + t->next = 0; + SwigPtrN++; + } + + /* Check for existing entry */ + + while (t->next) { + if ((strcmp(t->name,newtype) == 0)) { + if (cast) t->cast = cast; + return; + } + t = t->next; + } + + /* Now place entry (in sorted order) */ + + t1 = (SwigPtrType *) malloc(sizeof(SwigPtrType)); + t1->name = newtype; + t1->len = strlen(t1->name); + t1->cast = cast; + t1->next = 0; + t->next = t1; + SwigPtrSort = 0; +} + +/* Make a pointer value string */ + +SWIGSTATIC +void SWIG_MakePtr(char *_c, const void *_ptr, char *type) { + static char _hex[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + unsigned long _p, _s; + char _result[20], *_r; /* Note : a 64-bit hex number = 16 digits */ + _r = _result; + _p = (unsigned long) _ptr; + if (_p > 0) { + while (_p > 0) { + _s = _p & 0xf; + *(_r++) = _hex[_s]; + _p = _p >> 4; + } + *_r = '_'; + while (_r >= _result) + *(_c++) = *(_r--); + } else { + strcpy (_c, "NULL"); + } + if (_ptr) + strcpy (_c, type); +} + +/* Define for backwards compatibility */ + +#define _swig_make_hex SWIG_MakePtr + +/* Function for getting a pointer value */ + +SWIGSTATIC +char *SWIG_GetPtr(char *_c, void **ptr, char *_t) +{ + unsigned long _p; + char temp_type[256]; + char *name; + int i, len; + SwigPtrType *sp,*tp; + SwigCacheType *cache; + int start, end; + _p = 0; + + /* Pointer values must start with leading underscore */ + if (*_c == '_') { + _c++; + /* Extract hex value from pointer */ + while (*_c) { + if ((*_c >= '0') && (*_c <= '9')) + _p = (_p << 4) + (*_c - '0'); + else if ((*_c >= 'a') && (*_c <= 'f')) + _p = (_p << 4) + ((*_c - 'a') + 10); + else + break; + _c++; + } + + if (_t) { + if (strcmp(_t,_c)) { + if (!SwigPtrSort) { + qsort((void *) SwigPtrTable, SwigPtrN, sizeof(SwigPtrType), swigsort); + for (i = 0; i < 256; i++) { + SwigStart[i] = SwigPtrN; + } + for (i = SwigPtrN-1; i >= 0; i--) { + SwigStart[(int) (SwigPtrTable[i].name[1])] = i; + } + for (i = 255; i >= 1; i--) { + if (SwigStart[i-1] > SwigStart[i]) + SwigStart[i-1] = SwigStart[i]; + } + SwigPtrSort = 1; + for (i = 0; i < SWIG_CACHESIZE; i++) + SwigCache[i].stat = 0; + } + + /* First check cache for matches. Uses last cache value as starting point */ + cache = &SwigCache[SwigLastCache]; + for (i = 0; i < SWIG_CACHESIZE; i++) { + if (cache->stat) { + if (strcmp(_t,cache->name) == 0) { + if (strcmp(_c,cache->mapped) == 0) { + cache->stat++; + *ptr = (void *) _p; + if (cache->tp->cast) *ptr = (*(cache->tp->cast))(*ptr); + return (char *) 0; + } + } + } + SwigLastCache = (SwigLastCache+1) & SWIG_CACHEMASK; + if (!SwigLastCache) cache = SwigCache; + else cache++; + } + /* We have a type mismatch. Will have to look through our type + mapping table to figure out whether or not we can accept this datatype */ + + start = SwigStart[(int) _t[1]]; + end = SwigStart[(int) _t[1]+1]; + sp = &SwigPtrTable[start]; + while (start < end) { + if (swigcmp(_t,sp) == 0) break; + sp++; + start++; + } + if (start >= end) sp = 0; + /* Try to find a match for this */ + if (sp) { + while (swigcmp(_t,sp) == 0) { + name = sp->name; + len = sp->len; + tp = sp->next; + /* Try to find entry for our given datatype */ + while(tp) { + if (tp->len >= 255) { + return _c; + } + strcpy(temp_type,tp->name); + strncat(temp_type,_t+len,255-tp->len); + if (strcmp(_c,temp_type) == 0) { + + strcpy(SwigCache[SwigCacheIndex].mapped,_c); + strcpy(SwigCache[SwigCacheIndex].name,_t); + SwigCache[SwigCacheIndex].stat = 1; + SwigCache[SwigCacheIndex].tp = tp; + SwigCacheIndex = SwigCacheIndex & SWIG_CACHEMASK; + + /* Get pointer value */ + *ptr = (void *) _p; + if (tp->cast) *ptr = (*(tp->cast))(*ptr); + return (char *) 0; + } + tp = tp->next; + } + sp++; + /* Hmmm. Didn't find it this time */ + } + } + /* Didn't find any sort of match for this data. + Get the pointer value and return the received type */ + *ptr = (void *) _p; + return _c; + } else { + /* Found a match on the first try. Return pointer value */ + *ptr = (void *) _p; + return (char *) 0; + } + } else { + /* No type specified. Good luck */ + *ptr = (void *) _p; + return (char *) 0; + } + } else { + if (strcmp (_c, "NULL") == 0) { + *ptr = (void *) 0; + return (char *) 0; + } + *ptr = (void *) 0; + return _c; + } +} + +/* Compatibility mode */ + +#define _swig_get_hex SWIG_GetPtr + +#define SWIG_init initjoystick + +#define SWIG_name "joystick" + +extern int closeDevice(int); +extern int openDevice(char *); +extern int readEvents(int); +extern int getEventCount(int); +extern int getEventType(int, int); +extern int getEventNumber(int, int); +extern int getEventValue(int, int); +static PyObject *_wrap_closeDevice(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:closeDevice",&_arg0)) + return NULL; + _result = (int )closeDevice(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_openDevice(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + char * _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"s:openDevice",&_arg0)) + return NULL; + _result = (int )openDevice(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_readEvents(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:readEvents",&_arg0)) + return NULL; + _result = (int )readEvents(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventCount(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:getEventCount",&_arg0)) + return NULL; + _result = (int )getEventCount(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventType(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventType",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventType(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventNumber(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventNumber",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventNumber(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventValue(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventValue",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventValue(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyMethodDef joystickMethods[] = { + { "getEventValue", _wrap_getEventValue, 1 }, + { "getEventNumber", _wrap_getEventNumber, 1 }, + { "getEventType", _wrap_getEventType, 1 }, + { "getEventCount", _wrap_getEventCount, 1 }, + { "readEvents", _wrap_readEvents, 1 }, + { "openDevice", _wrap_openDevice, 1 }, + { "closeDevice", _wrap_closeDevice, 1 }, + { NULL, NULL } +}; +static PyObject *SWIG_globals; +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT(void,initjoystick)() { + PyObject *m, *d; + SWIG_globals = SWIG_newvarlink(); + m = Py_InitModule("joystick", joystickMethods); + d = PyModule_GetDict(m); +/* + * These are the pointer type-equivalency mappings. + * (Used by the SWIG pointer type-checker). + */ + SWIG_RegisterMapping("_signed_long","_long",0); + SWIG_RegisterMapping("_long","_unsigned_long",0); + SWIG_RegisterMapping("_long","_signed_long",0); + SWIG_RegisterMapping("_unsigned_long","_long",0); + SWIG_RegisterMapping("_signed_int","_int",0); + SWIG_RegisterMapping("_unsigned_short","_short",0); + SWIG_RegisterMapping("_signed_short","_short",0); + SWIG_RegisterMapping("_unsigned_int","_int",0); + SWIG_RegisterMapping("_short","_unsigned_short",0); + SWIG_RegisterMapping("_short","_signed_short",0); + SWIG_RegisterMapping("_int","_unsigned_int",0); + SWIG_RegisterMapping("_int","_signed_int",0); +} diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..8930736 --- /dev/null +++ b/src/makefile @@ -0,0 +1,44 @@ +#-------------------------------------------------------------- + +current: gripd_linux +clean: clean_linux + +#----------- Options (all OS) -------------------------------- + +MIDI = TRUE +#MIDI = FALSE +JOYSTICK = TRUE +#JOYSTICK = FALSE + +#----------- Settings (Linux) -------------------------------- + +MIDIOSSUBTYPE = ALSA +#MIDIOSSUBTYPE = OSS +PDINCLUDE = -I../../src +LINUXPYTHONINCLUDE = -I/usr/include/python2.2 +SYSTEMLIBDIR = /usr/lib + +#----------- Settings (Windows) ------------------------------- + +VC = "C:\Program Files\Microsoft Visual Studio\VC98" +PYTHONHOME = C:\python22 +PYTHONVER = 22 +PDNTSRCDIR = C:\pd-37\src +PDNTLDIR = C:\pd-37\bin + +#----------- Linux -------------------------------------------- + +gripd_linux: + make -f Makefile.Linux all +clean_linux: + make -f Makefile.Linux linux_clean + +#----------- Win32--------------------------------------------- + +gripd_nt: + nmake -f Makefile.NT all +clean_nt: + nmake -f Makefile.NT nt_clean + + + diff --git a/src/midi.cpp b/src/midi.cpp new file mode 100644 index 0000000..1d63446 --- /dev/null +++ b/src/midi.cpp @@ -0,0 +1,146 @@ +/* GrIPD v0.1.1 - Graphical Interface for Pure Data +** Copyright (C) 2003 Joseph A. Sarlo +** +** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** jsarlo@ucsd.edu +*/ + +#include "midiiolib.h" +#include +#ifndef NT +#include +#endif +#define MAXDEVS 16 +#define MAXEVENTS 4096 + +#ifndef VISUAL +using namespace std; +#endif + +static int eventCount[MAXDEVS]; +static int eventCommand[MAXEVENTS][MAXDEVS]; +static int eventP0[MAXEVENTS][MAXDEVS]; +static int eventP1[MAXEVENTS][MAXDEVS]; +static int eventP2[MAXEVENTS][MAXDEVS]; +static int eventP3[MAXEVENTS][MAXDEVS]; +static MidiInput mInput[MAXDEVS]; +static int devCount = 0; +static int devList[MAXDEVS]; + +int openDevice(int dev) { + int i, devId, numPorts; + + numPorts = MidiInPort::getNumPorts(); + if (dev >= numPorts || dev < 0) { + return (-1); + } + else { + if (devCount == 0) { + for (i = 0; i < MAXDEVS; i++) { + devList[i] = 0; + } + } + for (i = 0; i < MAXDEVS; i++) { + if (devList[i] == 0) { + devId = i; + i = MAXDEVS; + } + } + devCount++; + eventCount[devId] = 0; + devList[devId] = 1; + mInput[devId].setPort(dev); + mInput[devId].open(); + return (devId); + } +} + +int closeDevice(int devno) { + if (devList[devno]) { + devCount--; + devList[devno] = 0; +#ifndef LINUX + mInput[devno].close(); +#endif + return (1); + } + else + return (-1); +} + +int readEvents(int devno) { + int i; + MidiMessage message; + + if (devno < 0 || devno >= MAXDEVS) + return (-1); + eventCount[devno] = mInput[devno].getCount(); + if (eventCount[devno] > MAXEVENTS) { + eventCount[devno] = MAXEVENTS; + } + for (i = 0; i < eventCount[devno]; i++) { + message = mInput[devno].extract(); + eventCommand[i][devno] = message.getCommand(); + eventP0[i][devno] = message.getP0(); + eventP1[i][devno] = message.getP1(); + eventP2[i][devno] = message.getP2(); + eventP3[i][devno] = message.getP3(); + } + return (eventCount[devno]); +} + +int getEventCount(int devno) { + if (devno < 0 || devno >= MAXDEVS) + return (-1); + else + return (eventCount[devno]); +} + +int getEventCommand(int devno, int eNum) { + if (eNum < 0 || eNum >= eventCount[devno] || devno < 0 || devno >= MAXDEVS) + return (-1); + else + return eventCommand[eNum][devno]; +} + +int getEventP0(int devno, int eNum) { + if (eNum < 0 || eNum >= eventCount[devno] || devno < 0 || devno >= MAXDEVS) + return (-1); + else + return eventP0[eNum][devno]; +} + +int getEventP1(int devno, int eNum) { + if (eNum < 0 || eNum >= eventCount[devno] || devno < 0 || devno >= MAXDEVS) + return (-1); + else + return eventP1[eNum][devno]; +} + +int getEventP2(int devno, int eNum) { + if (eNum < 0 || eNum >= eventCount[devno] || devno < 0 || devno >= MAXDEVS) + return (-1); + else + return eventP2[eNum][devno]; +} + +int getEventP3(int devno, int eNum) { + if (eNum < 0 || eNum >= eventCount[devno] || devno < 0 || devno >= MAXDEVS) + return (-1); + else + return eventP3[eNum][devno]; +} + diff --git a/src/midi_wrap.c b/src/midi_wrap.c new file mode 100644 index 0000000..7b4ad15 --- /dev/null +++ b/src/midi_wrap.c @@ -0,0 +1,723 @@ +/* + * FILE : midi_wrap.c + * + * This file was automatically generated by : + * Simplified Wrapper and Interface Generator (SWIG) + * Version 1.1 (Patch 5) + * + * Portions Copyright (c) 1995-1998 + * The University of Utah and The Regents of the University of California. + * Permission is granted to distribute this file in any manner provided + * this notice remains intact. + * + * Do not make changes to this file--changes will be lost! + * + */ + + +#define SWIGCODE +/* Implementation : PYTHON */ + +#define SWIGPYTHON +#include +#include +/*********************************************************************** + * $Header: /home/zmoelnig/cvs2svn/pure-data/puredata_cvsbackup/extensions/gripd/src/midi_wrap.c,v 1.1.1.1 2005-11-10 05:52:09 eighthave Exp $ + * swig_lib/python/python.cfg + * + * This file contains coded needed to add variable linking to the + * Python interpreter. C variables are added as a new kind of Python + * datatype. + * + * Also contains supporting code for building python under Windows + * and things like that. + * + * $Log: not supported by cvs2svn $ + ************************************************************************/ + +#ifdef __cplusplus +#include "Python.h" +extern "C" { +#endif +#ifdef __cplusplus +} +#endif + +/* Definitions for Windows/Unix exporting */ +#if defined(__WIN32__) +# if defined(_MSC_VER) +# define SWIGEXPORT(a,b) __declspec(dllexport) a b +# else +# if defined(__BORLANDC__) +# define SWIGEXPORT(a,b) a _export b +# else +# define SWIGEXPORT(a,b) a b +# endif +# endif +#else +# define SWIGEXPORT(a,b) a b +#endif + +#ifdef SWIG_GLOBAL +#ifdef __cplusplus +#define SWIGSTATIC extern "C" +#else +#define SWIGSTATIC +#endif +#endif + +#ifndef SWIGSTATIC +#define SWIGSTATIC static +#endif + +typedef struct { + char *name; + PyObject *(*get_attr)(void); + int (*set_attr)(PyObject *); +} swig_globalvar; + +typedef struct swig_varlinkobject { + PyObject_HEAD + swig_globalvar **vars; + int nvars; + int maxvars; +} swig_varlinkobject; + +/* ---------------------------------------------------------------------- + swig_varlink_repr() + + Function for python repr method + ---------------------------------------------------------------------- */ + +static PyObject * +swig_varlink_repr(swig_varlinkobject *v) +{ + v = v; + return PyString_FromString(""); +} + +/* --------------------------------------------------------------------- + swig_varlink_print() + + Print out all of the global variable names + --------------------------------------------------------------------- */ + +static int +swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags) +{ + + int i = 0; + flags = flags; + fprintf(fp,"Global variables { "); + while (v->vars[i]) { + fprintf(fp,"%s", v->vars[i]->name); + i++; + if (v->vars[i]) fprintf(fp,", "); + } + fprintf(fp," }\n"); + return 0; +} + +/* -------------------------------------------------------------------- + swig_varlink_getattr + + This function gets the value of a variable and returns it as a + PyObject. In our case, we'll be looking at the datatype and + converting into a number or string + -------------------------------------------------------------------- */ + +static PyObject * +swig_varlink_getattr(swig_varlinkobject *v, char *n) +{ + int i = 0; + char temp[128]; + + while (v->vars[i]) { + if (strcmp(v->vars[i]->name,n) == 0) { + return (*v->vars[i]->get_attr)(); + } + i++; + } + sprintf(temp,"C global variable %s not found.", n); + PyErr_SetString(PyExc_NameError,temp); + return NULL; +} + +/* ------------------------------------------------------------------- + swig_varlink_setattr() + + This function sets the value of a variable. + ------------------------------------------------------------------- */ + +static int +swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) +{ + char temp[128]; + int i = 0; + while (v->vars[i]) { + if (strcmp(v->vars[i]->name,n) == 0) { + return (*v->vars[i]->set_attr)(p); + } + i++; + } + sprintf(temp,"C global variable %s not found.", n); + PyErr_SetString(PyExc_NameError,temp); + return 1; +} + +statichere PyTypeObject varlinktype = { +/* PyObject_HEAD_INIT(&PyType_Type) Note : This doesn't work on some machines */ + PyObject_HEAD_INIT(0) + 0, + "varlink", /* Type name */ + sizeof(swig_varlinkobject), /* Basic size */ + 0, /* Itemsize */ + 0, /* Deallocator */ + (printfunc) swig_varlink_print, /* Print */ + (getattrfunc) swig_varlink_getattr, /* get attr */ + (setattrfunc) swig_varlink_setattr, /* Set attr */ + 0, /* tp_compare */ + (reprfunc) swig_varlink_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_mapping*/ + 0, /* tp_hash */ +}; + +/* Create a variable linking object for use later */ + +SWIGSTATIC PyObject * +SWIG_newvarlink(void) +{ + swig_varlinkobject *result = 0; + result = PyMem_NEW(swig_varlinkobject,1); + varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */ + result->ob_type = &varlinktype; + /* _Py_NewReference(result); Does not seem to be necessary */ + result->nvars = 0; + result->maxvars = 64; + result->vars = (swig_globalvar **) malloc(64*sizeof(swig_globalvar *)); + result->vars[0] = 0; + result->ob_refcnt = 0; + Py_XINCREF((PyObject *) result); + return ((PyObject*) result); +} + +SWIGSTATIC void +SWIG_addvarlink(PyObject *p, char *name, + PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) +{ + swig_varlinkobject *v; + v= (swig_varlinkobject *) p; + + if (v->nvars >= v->maxvars -1) { + v->maxvars = 2*v->maxvars; + v->vars = (swig_globalvar **) realloc(v->vars,v->maxvars*sizeof(swig_globalvar *)); + if (v->vars == NULL) { + fprintf(stderr,"SWIG : Fatal error in initializing Python module.\n"); + exit(1); + } + } + v->vars[v->nvars] = (swig_globalvar *) malloc(sizeof(swig_globalvar)); + v->vars[v->nvars]->name = (char *) malloc(strlen(name)+1); + strcpy(v->vars[v->nvars]->name,name); + v->vars[v->nvars]->get_attr = get_attr; + v->vars[v->nvars]->set_attr = set_attr; + v->nvars++; + v->vars[v->nvars] = 0; +} + + + +/***************************************************************************** + * $Header: /home/zmoelnig/cvs2svn/pure-data/puredata_cvsbackup/extensions/gripd/src/midi_wrap.c,v 1.1.1.1 2005-11-10 05:52:09 eighthave Exp $ + * + * swigptr.swg + * + * This file contains supporting code for the SWIG run-time type checking + * mechanism. The following functions are available : + * + * SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)); + * + * Registers a new type-mapping with the type-checker. origtype is the + * original datatype and newtype is an equivalent type. cast is optional + * pointer to a function to cast pointer values between types (this + * is typically used to cast pointers from derived classes to base classes in C++) + * + * SWIG_MakePtr(char *buffer, void *ptr, char *typestring); + * + * Makes a pointer string from a pointer and typestring. The result is returned + * in buffer which is assumed to hold enough space for the result. + * + * char * SWIG_GetPtr(char *buffer, void **ptr, char *type) + * + * Gets a pointer value from a string. If there is a type-mismatch, returns + * a character string to the received type. On success, returns NULL. + * + * + * You can remap these functions by making a file called "swigptr.swg" in + * your the same directory as the interface file you are wrapping. + * + * These functions are normally declared static, but this file can be + * can be used in a multi-module environment by redefining the symbol + * SWIGSTATIC. + *****************************************************************************/ + +#include + +#ifdef SWIG_GLOBAL +#ifdef __cplusplus +#define SWIGSTATIC extern "C" +#else +#define SWIGSTATIC +#endif +#endif + +#ifndef SWIGSTATIC +#define SWIGSTATIC static +#endif + + +/* SWIG pointer structure */ + +typedef struct SwigPtrType { + char *name; /* Datatype name */ + int len; /* Length (used for optimization) */ + void *(*cast)(void *); /* Pointer casting function */ + struct SwigPtrType *next; /* Linked list pointer */ +} SwigPtrType; + +/* Pointer cache structure */ + +typedef struct { + int stat; /* Status (valid) bit */ + SwigPtrType *tp; /* Pointer to type structure */ + char name[256]; /* Given datatype name */ + char mapped[256]; /* Equivalent name */ +} SwigCacheType; + +/* Some variables */ + +static int SwigPtrMax = 64; /* Max entries that can be currently held */ + /* This value may be adjusted dynamically */ +static int SwigPtrN = 0; /* Current number of entries */ +static int SwigPtrSort = 0; /* Status flag indicating sort */ +static int SwigStart[256]; /* Starting positions of types */ + +/* Pointer table */ +static SwigPtrType *SwigPtrTable = 0; /* Table containing pointer equivalences */ + +/* Cached values */ + +#define SWIG_CACHESIZE 8 +#define SWIG_CACHEMASK 0x7 +static SwigCacheType SwigCache[SWIG_CACHESIZE]; +static int SwigCacheIndex = 0; +static int SwigLastCache = 0; + +/* Sort comparison function */ +static int swigsort(const void *data1, const void *data2) { + SwigPtrType *d1 = (SwigPtrType *) data1; + SwigPtrType *d2 = (SwigPtrType *) data2; + return strcmp(d1->name,d2->name); +} + +/* Binary Search function */ +static int swigcmp(const void *key, const void *data) { + char *k = (char *) key; + SwigPtrType *d = (SwigPtrType *) data; + return strncmp(k,d->name,d->len); +} + +/* Register a new datatype with the type-checker */ + +SWIGSTATIC +void SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)) { + + int i; + SwigPtrType *t = 0,*t1; + + /* Allocate the pointer table if necessary */ + + if (!SwigPtrTable) { + SwigPtrTable = (SwigPtrType *) malloc(SwigPtrMax*sizeof(SwigPtrType)); + SwigPtrN = 0; + } + /* Grow the table */ + if (SwigPtrN >= SwigPtrMax) { + SwigPtrMax = 2*SwigPtrMax; + SwigPtrTable = (SwigPtrType *) realloc((char *) SwigPtrTable,SwigPtrMax*sizeof(SwigPtrType)); + } + for (i = 0; i < SwigPtrN; i++) + if (strcmp(SwigPtrTable[i].name,origtype) == 0) { + t = &SwigPtrTable[i]; + break; + } + if (!t) { + t = &SwigPtrTable[SwigPtrN]; + t->name = origtype; + t->len = strlen(t->name); + t->cast = 0; + t->next = 0; + SwigPtrN++; + } + + /* Check for existing entry */ + + while (t->next) { + if ((strcmp(t->name,newtype) == 0)) { + if (cast) t->cast = cast; + return; + } + t = t->next; + } + + /* Now place entry (in sorted order) */ + + t1 = (SwigPtrType *) malloc(sizeof(SwigPtrType)); + t1->name = newtype; + t1->len = strlen(t1->name); + t1->cast = cast; + t1->next = 0; + t->next = t1; + SwigPtrSort = 0; +} + +/* Make a pointer value string */ + +SWIGSTATIC +void SWIG_MakePtr(char *_c, const void *_ptr, char *type) { + static char _hex[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + unsigned long _p, _s; + char _result[20], *_r; /* Note : a 64-bit hex number = 16 digits */ + _r = _result; + _p = (unsigned long) _ptr; + if (_p > 0) { + while (_p > 0) { + _s = _p & 0xf; + *(_r++) = _hex[_s]; + _p = _p >> 4; + } + *_r = '_'; + while (_r >= _result) + *(_c++) = *(_r--); + } else { + strcpy (_c, "NULL"); + } + if (_ptr) + strcpy (_c, type); +} + +/* Define for backwards compatibility */ + +#define _swig_make_hex SWIG_MakePtr + +/* Function for getting a pointer value */ + +SWIGSTATIC +char *SWIG_GetPtr(char *_c, void **ptr, char *_t) +{ + unsigned long _p; + char temp_type[256]; + char *name; + int i, len; + SwigPtrType *sp,*tp; + SwigCacheType *cache; + int start, end; + _p = 0; + + /* Pointer values must start with leading underscore */ + if (*_c == '_') { + _c++; + /* Extract hex value from pointer */ + while (*_c) { + if ((*_c >= '0') && (*_c <= '9')) + _p = (_p << 4) + (*_c - '0'); + else if ((*_c >= 'a') && (*_c <= 'f')) + _p = (_p << 4) + ((*_c - 'a') + 10); + else + break; + _c++; + } + + if (_t) { + if (strcmp(_t,_c)) { + if (!SwigPtrSort) { + qsort((void *) SwigPtrTable, SwigPtrN, sizeof(SwigPtrType), swigsort); + for (i = 0; i < 256; i++) { + SwigStart[i] = SwigPtrN; + } + for (i = SwigPtrN-1; i >= 0; i--) { + SwigStart[(int) (SwigPtrTable[i].name[1])] = i; + } + for (i = 255; i >= 1; i--) { + if (SwigStart[i-1] > SwigStart[i]) + SwigStart[i-1] = SwigStart[i]; + } + SwigPtrSort = 1; + for (i = 0; i < SWIG_CACHESIZE; i++) + SwigCache[i].stat = 0; + } + + /* First check cache for matches. Uses last cache value as starting point */ + cache = &SwigCache[SwigLastCache]; + for (i = 0; i < SWIG_CACHESIZE; i++) { + if (cache->stat) { + if (strcmp(_t,cache->name) == 0) { + if (strcmp(_c,cache->mapped) == 0) { + cache->stat++; + *ptr = (void *) _p; + if (cache->tp->cast) *ptr = (*(cache->tp->cast))(*ptr); + return (char *) 0; + } + } + } + SwigLastCache = (SwigLastCache+1) & SWIG_CACHEMASK; + if (!SwigLastCache) cache = SwigCache; + else cache++; + } + /* We have a type mismatch. Will have to look through our type + mapping table to figure out whether or not we can accept this datatype */ + + start = SwigStart[(int) _t[1]]; + end = SwigStart[(int) _t[1]+1]; + sp = &SwigPtrTable[start]; + while (start < end) { + if (swigcmp(_t,sp) == 0) break; + sp++; + start++; + } + if (start >= end) sp = 0; + /* Try to find a match for this */ + if (sp) { + while (swigcmp(_t,sp) == 0) { + name = sp->name; + len = sp->len; + tp = sp->next; + /* Try to find entry for our given datatype */ + while(tp) { + if (tp->len >= 255) { + return _c; + } + strcpy(temp_type,tp->name); + strncat(temp_type,_t+len,255-tp->len); + if (strcmp(_c,temp_type) == 0) { + + strcpy(SwigCache[SwigCacheIndex].mapped,_c); + strcpy(SwigCache[SwigCacheIndex].name,_t); + SwigCache[SwigCacheIndex].stat = 1; + SwigCache[SwigCacheIndex].tp = tp; + SwigCacheIndex = SwigCacheIndex & SWIG_CACHEMASK; + + /* Get pointer value */ + *ptr = (void *) _p; + if (tp->cast) *ptr = (*(tp->cast))(*ptr); + return (char *) 0; + } + tp = tp->next; + } + sp++; + /* Hmmm. Didn't find it this time */ + } + } + /* Didn't find any sort of match for this data. + Get the pointer value and return the received type */ + *ptr = (void *) _p; + return _c; + } else { + /* Found a match on the first try. Return pointer value */ + *ptr = (void *) _p; + return (char *) 0; + } + } else { + /* No type specified. Good luck */ + *ptr = (void *) _p; + return (char *) 0; + } + } else { + if (strcmp (_c, "NULL") == 0) { + *ptr = (void *) 0; + return (char *) 0; + } + *ptr = (void *) 0; + return _c; + } +} + +/* Compatibility mode */ + +#define _swig_get_hex SWIG_GetPtr + +#define SWIG_init initmidi + +#define SWIG_name "midi" +extern int openDevice(int ); +extern int closeDevice(int ); +extern int readEvents(int ); +extern int getEventCount(int ); +extern int getEventCommand(int ,int ); +extern int getEventP0(int ,int ); +extern int getEventP1(int ,int ); +extern int getEventP2(int ,int ); +extern int getEventP3(int ,int ); +static PyObject *_wrap_openDevice(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:openDevice",&_arg0)) + return NULL; + _result = (int )openDevice(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_closeDevice(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:closeDevice",&_arg0)) + return NULL; + _result = (int )closeDevice(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_readEvents(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:readEvents",&_arg0)) + return NULL; + _result = (int )readEvents(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventCount(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + + self = self; + if(!PyArg_ParseTuple(args,"i:getEventCount",&_arg0)) + return NULL; + _result = (int )getEventCount(_arg0); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventCommand(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventCommand",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventCommand(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventP0(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventP0",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventP0(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventP1(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventP1",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventP1(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventP2(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventP2",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventP2(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyObject *_wrap_getEventP3(PyObject *self, PyObject *args) { + PyObject * _resultobj; + int _result; + int _arg0; + int _arg1; + + self = self; + if(!PyArg_ParseTuple(args,"ii:getEventP3",&_arg0,&_arg1)) + return NULL; + _result = (int )getEventP3(_arg0,_arg1); + _resultobj = Py_BuildValue("i",_result); + return _resultobj; +} + +static PyMethodDef midiMethods[] = { + { "getEventP3", _wrap_getEventP3, 1 }, + { "getEventP2", _wrap_getEventP2, 1 }, + { "getEventP1", _wrap_getEventP1, 1 }, + { "getEventP0", _wrap_getEventP0, 1 }, + { "getEventCommand", _wrap_getEventCommand, 1 }, + { "getEventCount", _wrap_getEventCount, 1 }, + { "readEvents", _wrap_readEvents, 1 }, + { "closeDevice", _wrap_closeDevice, 1 }, + { "openDevice", _wrap_openDevice, 1 }, + { NULL, NULL } +}; +static PyObject *SWIG_globals; +#ifdef __cplusplus +extern "C" +#endif +SWIGEXPORT(void,initmidi)() { + PyObject *m, *d; + SWIG_globals = SWIG_newvarlink(); + m = Py_InitModule("midi", midiMethods); + d = PyModule_GetDict(m); +/* + * These are the pointer type-equivalency mappings. + * (Used by the SWIG pointer type-checker). + */ + SWIG_RegisterMapping("_signed_long","_long",0); + SWIG_RegisterMapping("_long","_unsigned_long",0); + SWIG_RegisterMapping("_long","_signed_long",0); + SWIG_RegisterMapping("_unsigned_long","_long",0); + SWIG_RegisterMapping("_signed_int","_int",0); + SWIG_RegisterMapping("_unsigned_short","_short",0); + SWIG_RegisterMapping("_signed_short","_short",0); + SWIG_RegisterMapping("_unsigned_int","_int",0); + SWIG_RegisterMapping("_short","_unsigned_short",0); + SWIG_RegisterMapping("_short","_signed_short",0); + SWIG_RegisterMapping("_int","_unsigned_int",0); + SWIG_RegisterMapping("_int","_signed_int",0); +} diff --git a/src/midiio/include/Array.cpp b/src/midiio/include/Array.cpp new file mode 100644 index 0000000..044ed2d --- /dev/null +++ b/src/midiio/include/Array.cpp @@ -0,0 +1,378 @@ +// +// Copyright 1997-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Sun May 11 20:41:28 GMT-0800 1997 +// Last Modified: Wed Jul 7 11:44:50 PDT 1999 (added setAll() function) +// Filename: ...sig/maint/code/base/Array/Array.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Array.cpp +// Syntax: C++ +// +// Description: An array which can grow dynamically. Array is derived from +// the Collection class and adds various mathematical operators +// to the Collection class. The Array template class is used for +// storing numbers of any type which can be added, multiplied +// and divided into one another. +// + +#ifndef _ARRAY_CPP_INCLUDED +#define _ARRAY_CPP_INCLUDED + +#include "Array.h" +#include +#include + + +////////////////////////////// +// +// Array::Array +// + +template +Array::Array(void) : Collection(4) { } + +template +Array::Array(int arraySize) : Collection(arraySize) { } + +template +Array::Array(Array& anArray) : Collection(anArray) { } + +template +Array::Array(int arraySize, type *anArray) : + Collection(arraySize, anArray) { } + + + + +////////////////////////////// +// +// Array::~Array +// + +template +Array::~Array() { } + + + +////////////////////////////// +// +// Array::setAll -- sets the contents of each element to the +// specified value +// + +template +void Array::setAll(type aValue) { + for (int i=0; i +type Array::sum(void) { + type theSum = 0; + for (int i=0; i +type Array::sum(int loIndex, int hiIndex) { + type theSum = 0; + for (int i=loIndex; i<=hiIndex; i++) { + theSum += array[i]; + } + return theSum; +} + + + +////////////////////////////// +// +// Array::zero(-1, -1) +// + +template +void Array::zero(int minIndex, int maxIndex) { + if (size == 0) return; + if (minIndex == -1) minIndex = 0; + if (maxIndex == -1) maxIndex = size-1; + + if (minIndex < 0 || maxIndex < 0 || minIndex > maxIndex || + maxIndex >= size) { + cerr << "Error in zero function: min = " << minIndex + << " max = " << maxIndex << " size = " << size << endl; + exit(1); + } + + for (int i=minIndex; i<=maxIndex; i++) { + array[i] = 0; + } +} + + +//////////////////////////////////////////////////////////////////////////// +// +// operators +// + + +template +int Array::operator==(const Array& aArray) { + if (getSize() != aArray.getSize()) { + return 0; + } + Array& t = *this; + int i; + for (i=0; i +Array& Array::operator=(const Array& anArray) { + if (allocSize < anArray.size) { + if (allocSize != 0) { + delete [] array; + } + allocSize = anArray.size; + size = anArray.size; + array = new type[size]; + allowGrowthQ = anArray.allowGrowthQ; + growthAmount = anArray.growthAmount; + maxSize = anArray.maxSize; + } + size = anArray.size; + for (int i=0; i +Array& Array::operator+=(const Array& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i +Array Array::operator+(const Array& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array bArray(*this); + bArray += anArray; + return bArray; +} + + +template +Array Array::operator+(type aNumber) const { + Array anArray(*this); + for (int i=0; i +Array& Array::operator-=(const Array& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i +Array Array::operator-(const Array& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array bArray(*this); + bArray -= anArray; + return bArray; +} + + +template +Array Array::operator-(void) const { + Array anArray(*this); + for (int i=0; i +Array Array::operator-(type aNumber) const { + Array anArray(*this); + for (int i=0; i +Array& Array::operator*=(const Array& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i +Array Array::operator*(const Array& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array bArray(*this); + bArray *= anArray; + return bArray; +} + + +template +Array Array::operator*(type aNumber) const { + Array anArray(*this); + for (int i=0; i +Array& Array::operator/=(const Array& anArray) { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + for (int i=0; i +Array Array::operator/(const Array& anArray) const { + if (size != anArray.size) { + cerr << "Error: different size arrays " << size << " and " + << anArray.size << endl; + exit(1); + } + + Array bArray(*this); + bArray /= anArray; + return bArray; +} + + +#endif /* _ARRAY_CPP_INCLUDED */ + + + +// md5sum: 8f52a167c93f51702ce316204fd6e722 - Array.cpp =css= 20030102 diff --git a/src/midiio/include/Array.h b/src/midiio/include/Array.h new file mode 100644 index 0000000..75e08eb --- /dev/null +++ b/src/midiio/include/Array.h @@ -0,0 +1,67 @@ +// +// Copyright 1997-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Sun May 11 20:33:13 GMT-0800 1997 +// Last Modified: Wed Jul 7 11:44:50 PDT 1999 (added setAll() function) +// Last Modified: Mon Jul 29 22:08:32 PDT 2002 (added operator==) +// Filename: ...sig/maint/code/base/Array/Array.h +// Web Address: http://sig.sapp.org/include/sigBase/Array.h +// Documentation: http://sig.sapp.org/doc/classes/Array +// Syntax: C++ +// +// Description: An array which can grow dynamically. Array is derived from +// the Collection class and adds various mathematical operators +// to the Collection class. The Array template class is used for +// storing numbers of any type which can be added, multiplied +// and divided into one another. +// + +#ifndef _ARRAY_H_INCLUDED +#define _ARRAY_H_INCLUDED + +#include "Collection.h" + + +template +class Array : public Collection { + public: + Array (void); + Array (int arraySize); + Array (Array& aArray); + Array (int arraySize, type *anArray); + ~Array (); + + void setAll (type aValue); + type sum (void); + type sum (int lowIndex, int hiIndex); + void zero (int minIndex = -1, int maxIndex = -1); + + int operator== (const Array& aArray); + Array& operator= (const Array& aArray); + Array& operator+= (const Array& aArray); + Array& operator-= (const Array& aArray); + Array& operator*= (const Array& aArray); + Array& operator/= (const Array& aArray); + + Array operator+ (const Array& aArray) const; + Array operator+ (type aNumber) const; + Array operator- (const Array& aArray) const; + Array operator- (void) const; + + Array operator- (type aNumber) const; + Array operator* (const Array& aArray) const; + Array operator* (type aNumber) const; + Array operator/ (const Array& aArray) const; +}; + + +#include "Array.cpp" /* necessary for templates */ + + + +#endif /* _ARRAY_H_INCLUDED */ + + + +// md5sum: 09d1b1f8e70ecde53f484548e48f33c3 - Array.h =css= 20030102 diff --git a/src/midiio/include/CircularBuffer.cpp b/src/midiio/include/CircularBuffer.cpp new file mode 100644 index 0000000..9f4aca6 --- /dev/null +++ b/src/midiio/include/CircularBuffer.cpp @@ -0,0 +1,291 @@ +// +// Copyright 1997-1998 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: 19 December 1997 +// Last Modified: Wed Jan 21 23:16:54 GMT-0800 1998 +// Filename: ...sig/maint/code/base/CircularBuffer/CircularBuffer.cpp +// Web Address: http://sig.sapp.org/src/sigBase/CircularBuffer.cpp +// Syntax: C++ +// +// Description: A Circular buffer designed to handle MIDI input, +// but able to store any type of object. Elements +// can be read out of the buffer in two ways. +// (1) from a read pointer which extracts the +// elements in order by following the write pointer, +// and (2) from an index operator related to the +// write pointer's location, for example, +// object[0] is the last value written into the +// buffer and object[-1] (or object[1]) is the +// item written just before that. +// +// + +#ifndef _CIRCULARBUFFER_CPP_INCLUDED +#define _CIRCULARBUFFER_CPP_INCLUDED + +#include "CircularBuffer.h" +#include +#include + + +////////////////////////////// +// +// CircularBuffer::CircularBuffer -- Constructor. +// + +template +CircularBuffer::CircularBuffer(void) { + size = 0; + buffer = NULL; + reset(); +} + + +template +CircularBuffer::CircularBuffer(int maxElements) { + if (maxElements < 0) { + std::cerr << "Error: cannot have a negative number of elements: " + << maxElements << std::endl; + exit(1); + } + if (maxElements == 0) { + size = 0; + buffer = NULL; + reset(); + } else { + size = maxElements; + buffer = new type[maxElements]; + reset(); + } +} + + +template +CircularBuffer::CircularBuffer(const CircularBuffer& anotherBuffer) { + size = anotherBuffer.size; + if (getSize() == 0) { + buffer = NULL; + reset(); + } else { + buffer = new type[getSize()]; + writeIndex = anotherBuffer.writeIndex; + readIndex = anotherBuffer.readIndex; + itemCount = anotherBuffer.itemCount; + for (int i=0; i +CircularBuffer::~CircularBuffer() { + if (buffer != NULL) { + delete [] buffer; + } +} + + + +////////////////////////////// +// +// CircularBuffer::capacity -- returns the number of items which +// can be added to the buffer. Returns a positive number +// if the buffer has empty locations available. Returns 0 if the +// buffer is 100% full. Returns a negative number if the +// buffer has overflowed. + +template +int CircularBuffer::capacity(void) const { + return getSize() - getCount(); +} + + + +////////////////////////////// +// +// CircularBuffer::extract -- reads the next value from the buffer. +// + +template +type CircularBuffer::extract(void) { + itemCount--; + if (itemCount < 0) { + std::cerr << "Error: no elements in buffer to extract." << std::endl; + exit(1); + } + increment(readIndex); + return buffer[readIndex]; +} + + + +////////////////////////////// +// +// CircularBuffer::getCount -- returns the number of elements +// between the write index and the read index. +// + +template +int CircularBuffer::getCount(void) const { + return itemCount; +} + + + +////////////////////////////// +// +// CircularBuffer::getSize -- returns the allocated size of the buffer. +// + +template +int CircularBuffer::getSize(void) const { + return size; +} + + + +////////////////////////////// +// +// CircularBuffer::insert -- add an element to the circular buffer +// + +template +void CircularBuffer::insert(const type& anItem) { + itemCount++; + increment(writeIndex); + buffer[writeIndex] = anItem; +} + + + +////////////////////////////// +// +// CircularBuffer::operator[] -- access an element relative to the +// currently written element +// + +template +type& CircularBuffer::operator[](int index) { + if (buffer == NULL) { + std::cerr << "Error: buffer has no allocated space" << std::endl; + exit(1); + } + int realIndex = (index < 0) ? -index : index; + if (realIndex >= getSize()) { + std::cerr << "Error: Invalid access: " << realIndex << ", maximum is " + << getSize()-1 << std::endl; + exit(1); + } + realIndex = writeIndex - realIndex; + + // should need to go through this loop a max of one time: + while (realIndex < 0) { + realIndex += getSize(); + } + + return buffer[realIndex]; +} + + + +////////////////////////////// +// +// CircularBuffer::read -- an alias for the extract function. +// + +template +type CircularBuffer::read(void) { + return extract(); +} + + + +////////////////////////////// +// +// CircularBuffer::reset -- throws out all previous data and +// sets the read/write/count to initial values. The size +// data variable must be valid before this function is +// called. +// + +template +void CircularBuffer::reset(void) { + readIndex = writeIndex = getSize() - 1; + itemCount = 0; +} + + + +////////////////////////////// +// +// CircularBuffer::setSize -- warning: will throw out all previous data +// stored in buffer. +// + +template +void CircularBuffer::setSize(int aSize) { + if (aSize < 0) { + std::cerr << "Error: cannot have a negative buffer size: " << aSize << std::endl; + exit(1); + } + if (buffer != NULL) { + delete [] buffer; + } + + if (aSize == 0) { + size = aSize; + buffer = NULL; + reset(); + } else { + size = aSize; + buffer = new type[aSize]; + reset(); + } +} + + + +////////////////////////////// +// +// CircularBuffer::write -- an alias for the insert function. +// + +template +void CircularBuffer::write(const type& anElement) { + write(anElement); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + +////////////////////////////// +// +// CircularBuffer::increment -- adds one to specified index and +// will automatically wrap the index when it gets too large. +// + +template +void CircularBuffer::increment(int& index) { + index++; + if (index >= getSize()) { + index = 0; + } +} + + +#endif /* _CIRCULARBUFFER_CPP_INCLUDED */ + + + +// md5sum: 31b2e8d6efe7398a12ddb0a1b5680ca2 - CircularBuffer.cpp =css= 20030102 diff --git a/src/midiio/include/CircularBuffer.h b/src/midiio/include/CircularBuffer.h new file mode 100644 index 0000000..6bb3071 --- /dev/null +++ b/src/midiio/include/CircularBuffer.h @@ -0,0 +1,66 @@ +// +// Copyright 1997-1998 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: 19 December 1997 +// Last Modified: Wed Jan 21 23:08:13 GMT-0800 1998 +// Filename: ...sig/maint/code/base/CircularBuffer/CircularBuffer.h +// Web Address: http://sig.sapp.org/include/sigBase/CircularBuffer.cpp +// Documentation: http://sig.sapp.org/doc/classes/CircularBuffer +// Syntax: C++ +// +// Description: A Circular buffer designed to handle MIDI input, +// but able to store any type of object. Elements +// can be read out of the buffer in two ways. +// (1) from a read pointer which extracts the +// elements in order by following the write pointer, +// and (2) from an index operator related to the +// write pointer's location, for example, +// object[0] is the last value written into the +// buffer and object[-1] (or object[1]) is the +// item written just before that. +// + +#ifndef _CIRCULARBUFFER_H_INCLUDED +#define _CIRCULARBUFFER_H_INCLUDED + + +template +class CircularBuffer { + public: + CircularBuffer (void); + CircularBuffer (int maxElements); + CircularBuffer (const CircularBuffer& + anotherBuffer); + ~CircularBuffer (); + + int capacity (void) const; + type extract (void); + int getCount (void) const; + int getSize (void) const; + void insert (const type& aMessage); + type& operator[] (int index); + type read (void); + void reset (void); + void setSize (int aSize); + void write (const type& aMessage); + + protected: + type* buffer; + int size; + int writeIndex; + int readIndex; + int itemCount; + + void increment (int& index); +}; + + +#include "CircularBuffer.cpp" + + + +#endif /* _CIRCULARBUFFER_H_INCLUDED */ + + + +// md5sum: 2857693ec37fdcb6df09db479faf110b - CircularBuffer.h =css= 20030102 diff --git a/src/midiio/include/Collection.cpp b/src/midiio/include/Collection.cpp new file mode 100644 index 0000000..74eef16 --- /dev/null +++ b/src/midiio/include/Collection.cpp @@ -0,0 +1,355 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Wed Apr 23 22:08:34 GMT-0800 1997 +// Last Modified: Fri Sep 14 15:50:52 PDT 2001 (added last() function) +// Filename: ...sig/maint/code/base/Collection/Collection.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Collection.cpp +// Syntax: C++ +// +// Description: A dynamic array which can grow as necessary. +// This class can hold any type of item, but the +// derived Array class is specifically for collections +// of numbers. +// + +#ifndef _COLLECTION_CPP_INCLUDED +#define _COLLECTION_CPP_INCLUDED + +#include "Collection.h" +#include +#include + + +////////////////////////////// +// +// Collection::Collection +// + +template +Collection::Collection(void) { + allocSize = 0; + size = 0; + array = NULL; + allowGrowthQ = 0; + growthAmount = 8; + maxSize = 0; +} + +template +Collection::Collection(int arraySize) { + array = new type[arraySize]; + size = arraySize; + allocSize = arraySize; + allowGrowthQ = 0; + growthAmount = arraySize; + maxSize = 0; +} + + +template +Collection::Collection(int arraySize, type *aCollection) { + size = arraySize; + allocSize = arraySize; + array = new type[size]; + for (int i=0; i +Collection::Collection(Collection& aCollection) { + size = aCollection.size; + allocSize = size; + array = new type[size]; + for (int i=0; i +Collection::~Collection() { + if (getAllocSize() != 0) { + delete [] array; + } +} + + + +////////////////////////////// +// +// Collection::allowGrowth +// default value: status = 1 +// + +template +void Collection::allowGrowth(int status) { + if (status == 0) { + allowGrowthQ = 0; + } else { + allowGrowthQ = 1; + } +} + + + +////////////////////////////// +// +// Collection::append +// + +template +void Collection::append(type& element) { + if (size == getAllocSize()) { + grow(); + } + array[size] = element; + size++; +} + +template +void Collection::appendcopy(type element) { + if (size == getAllocSize()) { + grow(); + } + array[size] = element; + size++; +} + +template +void Collection::append(type *element) { + if (size == getAllocSize()) { + grow(); + } + array[size] = *element; + size++; +} + + + +////////////////////////////// +// +// Collection::grow +// default parameter: growamt = -1 +// + +template +void Collection::grow(long growamt) { + allocSize += growamt > 0 ? growamt : growthAmount; + if (maxSize != 0 && getAllocSize() > maxSize) { + std::cerr << "Error: Maximum size allowed for array exceeded." << std::endl; + exit(1); + } + + type *temp = new type[getAllocSize()]; + for (int i=0; i +type* Collection::pointer(void) { + return array; +} + + + +////////////////////////////// +// +// Collection::getBase +// + +template +type* Collection::getBase(void) { + return array; +} + + + +////////////////////////////// +// +// Collection::getAllocSize +// + +template +long Collection::getAllocSize(void) const { + return allocSize; +} + + + +////////////////////////////// +// +// Collection::getSize -- +// + +template +long Collection::getSize(void) const { + return size; +} + + + +////////////////////////////// +// +// Collection::last -- +// + +template +type& Collection::last(void) { + return array[getSize()-1]; +} + + + +////////////////////////////// +// +// Collection::setAllocSize +// + +template +void Collection::setAllocSize(long aSize) { + if (aSize < getSize()) { + std::cerr << "Error: cannot set allocated size smaller than actual size." + << std::endl; + exit(1); + } + + if (aSize <= getAllocSize()) { + shrinkTo(aSize); + } else { + grow(aSize-getAllocSize()); + size = aSize; + } +} + + + +////////////////////////////// +// +// Collection::setGrowth +// default parameter: growth = -1 +// + +template +void Collection::setGrowth(long growth) { + if (growth > 0) { + growthAmount = growth; + } +} + + + +////////////////////////////// +// +// Collection::setSize +// + +template +void Collection::setSize(long newSize) { + if (newSize <= getAllocSize()) { + size = newSize; + } else { + grow(newSize-getAllocSize()); + size = newSize; + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Collection operators +// + +////////////////////////////// +// +// Collection::operator[] +// + +template +type& Collection::operator[](int elementIndex) { + if (allowGrowthQ && elementIndex == size) { + if (size == getAllocSize()) { + grow(); + } + size++; + } else if (elementIndex >= size) { + std::cerr << "Error: accessing invalid array location " + << elementIndex + << " Maximum is " << size-1 << std::endl; + exit(1); + } + return array[elementIndex]; +} + + +////////////////////////////// +// +// Collection::operator[] const +// + +template +type Collection::operator[](int elementIndex) const { + if (elementIndex >= size) { + std::cerr << "Error: accessing invalid array location " + << elementIndex + << " Maximum is " << size-1 << std::endl; + exit(1); + } + return array[elementIndex]; +} + +////////////////////////////// +// +// shrinkTo +// + +template +void Collection::shrinkTo(long aSize) { + if (aSize < getSize()) { + exit(1); + } + + type *temp = new type[aSize]; + for (int i=0; i allocSize) { + size = allocSize; + } +} + + +#endif /* _COLLECTION_CPP_INCLUDED */ + + + +// md5sum: 9929fee30b1bede4305e1fb46303ddc1 - Collection.cpp =css= 20030102 diff --git a/src/midiio/include/Collection.h b/src/midiio/include/Collection.h new file mode 100644 index 0000000..6775366 --- /dev/null +++ b/src/midiio/include/Collection.h @@ -0,0 +1,70 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Feb 5 19:42:53 PST 1997 +// Last Modified: Tue Apr 22 20:28:16 GMT-0800 1997 +// Last Modified: Fri Sep 14 15:50:52 PDT 2001 (added last() function) +// Filename: ...sig/maint/code/base/Collection/Collection.h +// Web Address: http://sig.sapp.org/include/sigBase/Collection.h +// Documentation: http://sig.sapp.org/doc/classes/Collection +// Syntax: C++ +// +// Description: A dynamic array which can grow as necessary. +// This class can hold any type of item, but the +// derived Array class is specifically for collections +// of numbers. +// + +#ifndef _COLLECTION_H_INCLUDED +#define _COLLECTION_H_INCLUDED + + +template +class Collection { + public: + Collection (void); + Collection (int arraySize); + Collection (int arraySize, type *aCollection); + Collection (Collection& aCollection); + ~Collection (); + + void allowGrowth (int status = 1); + void append (type& element); + void appendcopy (type element); + void append (type* element); + type *getBase (void); + long getAllocSize (void) const; + long getSize (void) const; + type *pointer (void); + void setAllocSize (long aSize); + void setGrowth (long growth); + void setSize (long newSize); + type& operator[] (int arrayIndex); + type operator[] (int arrayIndex) const; + void grow (long growamt = -1); + type& last (void); + + + protected: + long size; // actual array size + long allocSize; // maximum allowable array size + type *array; // where the array data is stored + char allowGrowthQ; // allow/disallow growth + long growthAmount; // number of elements to grow by if index + // element one beyond max size is accessed + long maxSize; // the largest size the array is allowed + // to grow to, if 0, then ignore max + + void shrinkTo (long aSize); +}; + + +#include "Collection.cpp" + + + +#endif /* _COLLECTION_H_INCLUDED */ + + + +// md5sum: 01bec04835c0bd117f40c2bfe51c4abd - Collection.h =css= 20030102 diff --git a/src/midiio/include/FileIO.h b/src/midiio/include/FileIO.h new file mode 100644 index 0000000..fdec5de --- /dev/null +++ b/src/midiio/include/FileIO.h @@ -0,0 +1,148 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Fri May 9 22:30:32 PDT 1997 +// Last Modified: Sun Dec 14 05:26:16 GMT-0800 1997 +// Filename: ...sig/maint/code/base/FileIO/FileIO.h +// Web Address: http://sig.sapp.org/include/sigBase/FileIO.h +// Documentation: http://sig.sapp.org/doc/classes/FileIO +// Syntax: C++ +// +// Description: Derived from the fstream class, this class has +// functions which allow writing binary files in +// both little and big endian formats. Useful for +// writing files such as soundfiles and MIDI files +// which require numbers to be stored in a particular +// endian format. +// + +#ifndef _FILEIO_H_INCLUDED +#define _FILEIO_H_INCLUDED + + +#include + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned int uint; + +// templates would be nice to use here, but they don't seem +// to work intuitively... + +class FileIO : public std::fstream { + public: + FileIO (void); + FileIO (const char* filename, std::ios::openmode state); + ~FileIO (); + + void readBigEndian (char& aNumber); + void readBigEndian (uchar& aNumber); + void readBigEndian (short& aNumber); + void readBigEndian (ushort& aNumber); + void readBigEndian (long& aNumber); + void readBigEndian (ulong& aNumber); + void readBigEndian (int& aNumber); + void readBigEndian (uint& aNumber); + void readBigEndian (float& aNumber); + void readBigEndian (double& aNumber); + + void readLittleEndian (char& aNumber); + void readLittleEndian (uchar& aNumber); + void readLittleEndian (short& aNumber); + void readLittleEndian (ushort& aNumber); + void readLittleEndian (long& aNumber); + void readLittleEndian (ulong& aNumber); + void readLittleEndian (int& aNumber); + void readLittleEndian (uint& aNumber); + void readLittleEndian (float& aNumber); + void readLittleEndian (double& aNumber); + + void readMachineEndian (char& aNumber); + void readMachineEndian (uchar& aNumber); + void readMachineEndian (short& aNumber); + void readMachineEndian (ushort& aNumber); + void readMachineEndian (long& aNumber); + void readMachineEndian (ulong& aNumber); + void readMachineEndian (int& aNumber); + void readMachineEndian (uint& aNumber); + void readMachineEndian (float& aNumber); + void readMachineEndian (double& aNumber); + + void readNotMachineEndian (char& aNumber); + void readNotMachineEndian (uchar& aNumber); + void readNotMachineEndian (short& aNumber); + void readNotMachineEndian (ushort& aNumber); + void readNotMachineEndian (long& aNumber); + void readNotMachineEndian (ulong& aNumber); + void readNotMachineEndian (int& aNumber); + void readNotMachineEndian (uint& aNumber); + void readNotMachineEndian (float& aNumber); + void readNotMachineEndian (double& aNumber); + + void writeBigEndian (char aNumber); + void writeBigEndian (uchar aNumber); + void writeBigEndian (short aNumber); + void writeBigEndian (ushort aNumber); + void writeBigEndian (long aNumber); + void writeBigEndian (ulong aNumber); + void writeBigEndian (int aNumber); + void writeBigEndian (uint aNumber); + void writeBigEndian (float aNumber); + void writeBigEndian (double aNumber); + + void writeLittleEndian (char aNumber); + void writeLittleEndian (uchar aNumber); + void writeLittleEndian (short aNumber); + void writeLittleEndian (ushort aNumber); + void writeLittleEndian (long aNumber); + void writeLittleEndian (ulong aNumber); + void writeLittleEndian (int aNumber); + void writeLittleEndian (uint aNumber); + void writeLittleEndian (float aNumber); + void writeLittleEndian (double aNumber); + + void writeMachineEndian (char aNumber); + void writeMachineEndian (uchar aNumber); + void writeMachineEndian (short aNumber); + void writeMachineEndian (ushort aNumber); + void writeMachineEndian (long aNumber); + void writeMachineEndian (ulong aNumber); + void writeMachineEndian (int aNumber); + void writeMachineEndian (uint aNumber); + void writeMachineEndian (float aNumber); + void writeMachineEndian (double aNumber); + + void writeNotMachineEndian (char aNumber); + void writeNotMachineEndian (uchar aNumber); + void writeNotMachineEndian (short aNumber); + void writeNotMachineEndian (ushort aNumber); + void writeNotMachineEndian (long aNumber); + void writeNotMachineEndian (ulong aNumber); + void writeNotMachineEndian (int aNumber); + void writeNotMachineEndian (uint aNumber); + void writeNotMachineEndian (float aNumber); + void writeNotMachineEndian (double aNumber); + + protected: + + char flipBytes (char aNumber); + uchar flipBytes (uchar aNumber); + short flipBytes (short aNumber); + ushort flipBytes (ushort aNumber); + long flipBytes (long aNumber); + ulong flipBytes (ulong aNumber); + int flipBytes (int aNumber); + uint flipBytes (uint aNumber); + float flipBytes (float aNumber); + double flipBytes (double aNumber); + +}; + + + +#endif /* _FILEIO_H_INCLUDED */ + + + +// md5sum: 0a146ebe5c6bd0850be973f612827d20 - FileIO.h =css= 20030102 diff --git a/src/midiio/include/MidiFile.h b/src/midiio/include/MidiFile.h new file mode 100644 index 0000000..10794d5 --- /dev/null +++ b/src/midiio/include/MidiFile.h @@ -0,0 +1,108 @@ +// +// Copyright 1999-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Fri Nov 26 14:12:01 PST 1999 +// Last Modified: Fri Dec 2 13:26:44 PST 1999 +// Last Modified: Fri Nov 10 12:13:15 PST 2000 (added some more editing cap.) +// Last Modified: Thu Jan 10 10:03:39 PST 2002 (added allocateEvents()) +// Last Modified: Mon Jun 10 22:43:10 PDT 2002 (added clear()) +// Filename: ...sig/include/sigInfo/MidiFile.h +// Web Address: http://sig.sapp.org/include/sigInfo/MidiFile.h +// Syntax: C++ +// +// Description: A class which can read/write Standard MIDI files. +// MIDI data is stored by track in an array. This +// class is used for example in the MidiPerform class. +// + +#ifndef _MIDIfILE_H_INCLUDED +#define _MIDIfILE_H_INCLUDED + +#include "FileIO.h" +#include "Array.h" +#include "Collection.h" + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +#define TIME_STATE_DELTA 0 +#define TIME_STATE_ABSOLUTE 1 + +#define TRACK_STATE_SPLIT 0 +#define TRACK_STATE_JOINED 1 + + +class _MFEvent { + public: + _MFEvent (void); + _MFEvent (int command); + _MFEvent (int command, int param1); + _MFEvent (int command, int param1, int param2); + _MFEvent (int track, int command, int param1, int param2); + _MFEvent (int aTime, int aTrack, int command, int param1, int param2); + ~_MFEvent (); + int time; + int track; + Array data; +}; + + + +class MidiFile { + public: + MidiFile (void); + MidiFile (char* aFile); + ~MidiFile (); + + void absoluteTime (void); + int addEvent (int aTrack, int aTime, + Array& midiData); + int addTrack (void); + int addTrack (int count); + void allocateEvents (int track, int aSize); + void deltaTime (void); + void deleteTrack (int aTrack); + void erase (void); + void clear (void); + _MFEvent& getEvent (int aTrack, int anIndex); + int getTimeState (void); + int getTrackState (void); + int getTicksPerQuarterNote (void); + int getTrackCount (void); + int getNumTracks (void); + int getNumEvents (int aTrack); + void joinTracks (void); + void mergeTracks (int aTrack1, int aTrack2); + int read (char* aFile); + void setTicksPerQuarterNote (int ticks); + void sortTrack (Collection<_MFEvent>& trackData); + void sortTracks (void); + void splitTracks (void); + int write (const char* aFile); + + protected: + Collection*> events; // midi file events + int ticksPerQuarterNote; // time base of file + int trackCount; // # of tracks in file + int theTrackState; // joined or split + int theTimeState; // absolute or delta + char* readFileName; // read file name + + private: + void extractMidiData (FileIO& inputfile, Array& array, + uchar& runningCommand); + ulong extractVlvTime (FileIO& inputfile); + ulong unpackVLV (uchar a, uchar b, uchar c, uchar d, uchar e); + void writeVLValue (long aValue, Array& data); +}; + + +int eventcompare(const void* a, const void* b); +std::ostream& operator<<(std::ostream& out, MidiFile& aMidiFile); + +#endif /* _MIDIfILE_H_INCLUDED */ + + + +// md5sum: ff46e64698e2d9e88ebeef3efa9927d0 - MidiFile.h =css= 20030102 diff --git a/src/midiio/include/MidiFileWrite.h b/src/midiio/include/MidiFileWrite.h new file mode 100644 index 0000000..a213fdf --- /dev/null +++ b/src/midiio/include/MidiFileWrite.h @@ -0,0 +1,61 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Mar 15 10:55:56 GMT-0800 1998 +// Last Modified: Sun Mar 15 10:55:56 GMT-0800 1998 +// Filename: ...sig/code/control/MidiFileWrite/MidiFileWrite.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiFileWrite.h +// Syntax: C++ +// +// Description: The MidiFileWrite class will write out a Type 0 MidiFile. +// Used for recording MIDI data streams into Standard +// MIDI files. +// + +#ifndef _MIDIFILEWRITE_INCLUDED +#define _MIDIFILEWRITE_INCLUDED + + +#include "FileIO.h" + + +class MidiFileWrite { + public: + MidiFileWrite (void); + MidiFileWrite (const char* aFilename, int startTime = -1); + ~MidiFileWrite (); + + void close (void); + void setup (const char* aFilename, int startTime = -1); + void start (int startTime = -1); + void writeAbsolute (int aTime, int command, int p1, int p2); + void writeAbsolute (int aTime, int command, int p1); + void writeAbsolute (int aTime, int command); + void writeRaw (uchar aByte); + void writeRaw (uchar aByte, uchar Byte); + void writeRaw (uchar aByte, uchar Byte, uchar cByte); + void writeRaw (uchar aByte, uchar Byte, uchar cByte, + uchar dByte); + void writeRaw (uchar aByte, uchar Byte, uchar cByte, + uchar dByte, uchar eByte); + void writeRaw (uchar* anArray, int arraySize); + void writeRelative (int aTime, int command, int p1, int p2); + void writeRelative (int aTime, int command, int p1); + void writeRelative (int aTime, int command); + void writeVLValue (long aValue); + + + protected: + FileIO *midifile; // file stream for MIDI file + long trackSize; // size count for MIDI track + int lastPlayTime; // for calculating delta times + int openQ; // for checking file status + +}; + + + +#endif /* _MIDIFILEWRITE_INCLUDED */ + + + +// md5sum: 44ac572078bff648d096c7e7867d1b3c - MidiFileWrite.h =css= 20030102 diff --git a/src/midiio/include/MidiIO.h b/src/midiio/include/MidiIO.h new file mode 100644 index 0000000..80c9168 --- /dev/null +++ b/src/midiio/include/MidiIO.h @@ -0,0 +1,58 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 21 December 1997 +// Last Modified: Sun Jan 25 15:44:35 GMT-0800 1998 +// Filename: ...sig/code/control/MidiIO/MidiIO.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiIO.h +// Syntax: C++ +// +// Description: A unified class for MidiInput and MidiOutput that handles +// MIDI input and output connections. The Synthesizer +// and RadioBaton classes are derived from this class. +// + +#ifndef _MIDIIO_H_INCLUDED +#define _MIDIIO_H_INCLUDED + + +#include "MidiInput.h" +#include "MidiOutput.h" + + +class MidiIO : public MidiOutput, public MidiInput { + public: + MidiIO (void); + MidiIO (int outPort, int inPort); + ~MidiIO (); + + void close (void); + void closeInput (void); + void closeOutput (void); + int getChannelInOffset (void) const; + int getChannelOutOffset (void) const; + int getInputPort (void); + int getInputTrace (void); + int getNumInputPorts (void); + int getNumOutputPorts (void); + int getOutputPort (void); + int getOutputTrace (void); + int open (void); + int openInput (void); + int openOutput (void); + void setChannelOffset (int anOffset); + void setInputPort (int aPort); + void setInputTrace (int aState); + void setOutputPort (int aPort); + void setOutputTrace (int aState); + void toggleInputTrace (void); + void toggleOutputTrace (void); + +}; + + + +#endif /* _MIDIIO_H_INCLUDED */ + + + +// md5sum: 9f6122405c4d9e83994457210217ff22 - MidiIO.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort.h b/src/midiio/include/MidiInPort.h new file mode 100644 index 0000000..ac225c4 --- /dev/null +++ b/src/midiio/include/MidiInPort.h @@ -0,0 +1,98 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Jan 21 22:35:31 GMT-0800 1998 +// Last Modified: Thu Jan 22 23:13:54 GMT-0800 1998 +// Last Modified: Sat Nov 7 16:09:18 PST 1998 +// Last Modified: Tue Jun 29 16:14:50 PDT 1999 (added Sysex input) +// Last Modified: Tue May 23 23:08:44 PDT 2000 (oss/alsa selection added) +// Filename: ...sig/maint/code/control/MidiInPort/MidiInPort.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of an +// operating-system specific MIDI input method. +// Provides control of all low-level MIDI input +// functionality such that it will work on all +// computers in the same manner. +// + +#ifndef _MIDIINPORT_H_INCLUDED +#define _MIDIINPORT_H_INCLUDED + + +#include "MidiMessage.h" + +#ifdef VISUAL + #define MIDIINPORT MidiInPort_visual + #include "MidiInPort_visual.h" +#elif defined(LINUX) && defined(ALSA) && defined(OSS) + #define MIDIINPORT MidiInPort_linux + #include "MidiInPort_linux.h" +#elif defined(LINUX) && defined(ALSA) && !defined(OSS) + #define MIDIINPORT MidiInPort_alsa + #include "MidiInPort_alsa.h" +#elif defined (LINUX) && defined(OSS) && !defined(ALSA) + #define MIDIINPORT MidiInPort_oss + #include "MidiInPort_oss.h" +#elif defined(LINUX) + #define MIDIINPORT MidiInPort_oss + #include "MidiInPort_oss.h" +#else + #define MIDIINPORT MidiInPort_unsupported + #include "MidiInPort_unsupported.h" +#endif + + +class MidiInPort : protected MIDIINPORT { + public: + MidiInPort (void) : MIDIINPORT() {} + MidiInPort (int aPort, int autoOpen = 1) : + MIDIINPORT(aPort, autoOpen) {} + ~MidiInPort() { } + + void clearSysex(void) { MIDIINPORT::clearSysex(); } + void clearSysex(int buffer) { MIDIINPORT::clearSysex(buffer); } + void close(void) { MIDIINPORT::close(); } + void closeAll(void) { MIDIINPORT::closeAll(); } + MidiMessage extract(void) { return MIDIINPORT::extract(); } + int getBufferSize(void) { return MIDIINPORT::getBufferSize(); } + int getChannelOffset(void) const { + return MIDIINPORT::getChannelOffset(); } + int getCount(void) { return MIDIINPORT::getCount(); } + const char* getName(void) { return MIDIINPORT::getName(); } + static const char* getName(int i) { return MIDIINPORT::getName(i); } + static int getNumPorts(void) { + return MIDIINPORT::getNumPorts(); } + int getPort(void) { return MIDIINPORT::getPort(); } + int getPortStatus(void){ + return MIDIINPORT::getPortStatus(); } + uchar* getSysex(int buffer) { return MIDIINPORT::getSysex(buffer); } + int getSysexSize(int buffer) { return MIDIINPORT::getSysexSize(buffer); } + int getTrace(void) { return MIDIINPORT::getTrace(); } + void insert(const MidiMessage& aMessage) { + MIDIINPORT::insert(aMessage); } + int installSysex(uchar* anArray, int aSize) { + return MIDIINPORT::installSysex(anArray, aSize); } + int open(void) { return MIDIINPORT::open(); } + MidiMessage& operator[](int index) { + return MIDIINPORT::message(index); } + void pause(void) { MIDIINPORT::pause(); } + void setBufferSize(int aSize) { + MIDIINPORT::setBufferSize(aSize); } + void setChannelOffset(int anOffset) { + MIDIINPORT::setChannelOffset(anOffset); } + void setAndOpenPort(int aPort) { setPort(aPort); open(); } + void setPort(int aPort) { MIDIINPORT::setPort(aPort); } + int setTrace(int aState) { + return MIDIINPORT::setTrace(aState); } + void toggleTrace(void) { MIDIINPORT::toggleTrace(); } + void unpause(void) { MIDIINPORT::unpause(); } +}; + + + +#endif /* _MIDIINPORT_H_INCLUDED */ + + + +// md5sum: 96f8a2b4411a356d1b73cd96421b8931 - MidiInPort.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_alsa.h b/src/midiio/include/MidiInPort_alsa.h new file mode 100644 index 0000000..b321600 --- /dev/null +++ b/src/midiio/include/MidiInPort_alsa.h @@ -0,0 +1,107 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun May 14 22:05:27 PDT 2000 +// Last Modified: Sat Oct 13 16:11:24 PDT 2001 (updated for ALSA 0.9) +// Last Modified: Sat Nov 2 20:35:50 PST 2002 (added #ifdef ALSA) +// Filename: ...sig/maint/code/control/MidiInPort/linux/MidiInPort_alsa.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_alsa.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifndef _MIDIINPORT_ALSA_H_INCLUDED +#define _MIDIINPORT_ALSA_H_INCLUDED + +#ifdef LINUX +#ifdef ALSA + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" +#include "Sequencer_alsa.h" +#include "SigTimer.h" +#include + +typedef unsigned char uchar; +typedef void (*MIDI_Callback_function)(int arrivalPort); + + +class MidiInPort_alsa : public Sequencer_alsa { + public: + MidiInPort_alsa (void); + MidiInPort_alsa (int aPort, int autoOpen = 1); + ~MidiInPort_alsa (); + + void clearSysex (int buffer); + void clearSysex (void); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + static Array threadinitport; + + protected: + int port; // the port to which this object belongs + + static MIDI_Callback_function callbackFunction; + + static int installSysexPrivate (int port, + uchar* anArray, int aSize); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* trace; // for verifying input + static std::ostream* tracedisplay; // stream for displaying trace + static int numDevices; // number of input ports + static CircularBuffer** midiBuffer; // MIDI storage frm ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* pauseQ; // for adding items to Buffer or not + static SigTimer midiTimer; // for timing MIDI input + static Array midiInThread; // for MIDI input thread function + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + + + friend void *interpretMidiInputStreamPrivateALSA(void * x); + +}; + + +#endif /* ALSA */ +#endif /* LINUX */ + +#endif /* _MIDIINPORT_ALSA_H_INCLUDED */ + + + +// md5sum: 260a0accd6b08b638a00904c382293bc - MidiInPort_alsa.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_alsa05.h b/src/midiio/include/MidiInPort_alsa05.h new file mode 100644 index 0000000..27af569 --- /dev/null +++ b/src/midiio/include/MidiInPort_alsa05.h @@ -0,0 +1,107 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun May 14 22:05:27 PDT 2000 +// Last Modified: Wed Oct 3 22:28:20 PDT 2001 (frozen for ALSA 0.5) +// Last Modified: Thu Jan 2 18:55:12 PST 2003 (added #ifdef ALSA05) +// Filename: ...sig/maint/code/control/MidiInPort/linux/MidiInPort_alsa05.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_alsa05.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifndef _MIDIINPORT_ALSA05_H_INCLUDED +#define _MIDIINPORT_ALSA05_H_INCLUDED + +#ifdef LINUX +#ifdef ALSA05 + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" +#include "Sequencer_alsa05.h" +#include "SigTimer.h" +#include + +typedef unsigned char uchar; +typedef void (*MIDI_Callback_function)(int arrivalPort); + + +class MidiInPort_alsa05 : public Sequencer_alsa05 { + public: + MidiInPort_alsa05 (void); + MidiInPort_alsa05 (int aPort, int autoOpen = 1); + ~MidiInPort_alsa05 (); + + void clearSysex (int buffer); + void clearSysex (void); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + static Array threadinitport; + + protected: + int port; // the port to which this object belongs + + static MIDI_Callback_function callbackFunction; + + static int installSysexPrivate (int port, + uchar* anArray, int aSize); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* trace; // for verifying input + static ostream* tracedisplay; // stream for displaying trace + static int numDevices; // number of input ports + static CircularBuffer** midiBuffer; // MIDI storage frm ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* pauseQ; // for adding items to Buffer or not + static SigTimer midiTimer; // for timing MIDI input + static Array midiInThread; // for MIDI input thread function + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + + + friend void *interpretMidiInputStreamPrivateALSA05(void * x); + +}; + + +#endif /* ALSA05 */ +#endif /* LINUX */ + +#endif /* _MIDIINPORT_ALSA05_H_INCLUDED */ + + + +// md5sum: 7b85b4a658c6f1d45dc1da7752f25cae - MidiInPort_alsa05.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_linux.h b/src/midiio/include/MidiInPort_linux.h new file mode 100644 index 0000000..589d27a --- /dev/null +++ b/src/midiio/include/MidiInPort_linux.h @@ -0,0 +1,94 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun May 14 22:30:04 PDT 2000 +// Last Modified: Thu May 18 23:36:07 PDT 2000 (added ifdef LINUX lines) +// Last Modified: Sat Nov 2 20:37:49 PST 2002 (added ifdef ALSA OSS) +// Filename: ...sig/maint/code/control/MidiInPort/MidiInPort_linux.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_linux.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of an +// operating-system specific MIDI input method. +// Provides control of all low-level MIDI input +// functionality such that it will work on all +// computers in the same manner. +// + +#ifndef _MIDIINPORT_LINUX_H_INCLUDED +#define _MIDIINPORT_LINUX_H_INCLUDED + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#define MIDI_IN_UNKNOWN_SELECT 0 +#define MIDI_IN_OSS_SELECT 1 +#define MIDI_IN_ALSA_SELECT 2 + +#include "MidiInPort_oss.h" +#include "MidiInPort_alsa.h" +#include "MidiInPort_unsupported.h" +#include "MidiMessage.h" + + +class MidiInPort_linux { + public: + MidiInPort_linux(void); + MidiInPort_linux(int aPort, int autoOpen = 1); + ~MidiInPort_linux(); + + void clearSysex (void); + void clearSysex (int buffer); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + MidiMessage& operator[] (int index); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setAndOpenPort (int aPort); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + static int getSelect (void); + static int selectOSS (void); + static int selectALSA (void); + static int selectUnknown (void); + + private: + + static int current; // the type of MIDI out selected + static int alsaQ; // boolean for if ALSA is present + static int ossQ; // boolean for if OSS is present + static int objectCount; // keeps track of static variables + + static MidiInPort_oss *oss_input; + static MidiInPort_alsa *alsa_input; + static MidiInPort_unsupported *unknown_input; + + void determineDrivers (void); +}; + +#endif /* ALSA and OSS def */ +#endif /* LINUX def */ + +#endif /* _MIDIINPORT_LINUX_H_INCLUDED */ + + +// md5sum: cc3608fb63ccf222f018efc89a4275f0 - MidiInPort_linux.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_oss.h b/src/midiio/include/MidiInPort_oss.h new file mode 100644 index 0000000..ffa5666 --- /dev/null +++ b/src/midiio/include/MidiInPort_oss.h @@ -0,0 +1,105 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Fri Jan 8 08:33:57 PST 1999 +// Last Modified: Fri Jan 8 08:34:01 PST 1999 +// Last Modified: Tue Jun 29 16:18:02 PDT 1999 (added sysex capability) +// Last Modified: Wed May 10 17:10:05 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/maint/code/control/MidiInPort/linux/MidiInPort_oss.h +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_oss.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux OSS sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifndef _MIDIINPORT_OSS_H_INCLUDED +#define _MIDIINPORT_OSS_H_INCLUDED + +#ifdef LINUX + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" +#include "Sequencer_oss.h" +#include "SigTimer.h" +#include + +typedef unsigned char uchar; +typedef void (*MIDI_Callback_function)(int arrivalPort); + + +class MidiInPort_oss : public Sequencer_oss { + public: + MidiInPort_oss (void); + MidiInPort_oss (int aPort, int autoOpen = 1); + ~MidiInPort_oss (); + + void clearSysex (int buffer); + void clearSysex (void); + void close (void); + void close (int i) { close(); } + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + protected: + int port; // the port to which this object belongs + + static MIDI_Callback_function callbackFunction; + + static int installSysexPrivate (int port, + uchar* anArray, int aSize); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* trace; // for verifying input + static std::ostream* tracedisplay; // stream for displaying trace + static int numDevices; // number of input ports + static CircularBuffer** midiBuffer; // MIDI storage frm ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* pauseQ; // for adding items to Buffer or not + static SigTimer midiTimer; // for timing MIDI input + static pthread_t midiInThread; // for MIDI input thread function + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + + + friend void *interpretMidiInputStreamPrivate(void * x); + +}; + + +#endif /* LINUX */ + +#endif /* _MIDIINPORT_OSS_H_INCLUDED */ + + + +// md5sum: 05331ff5c3806fc753ebebaeffa3c377 - MidiInPort_oss.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_unsupported.h b/src/midiio/include/MidiInPort_unsupported.h new file mode 100644 index 0000000..1f3bcf0 --- /dev/null +++ b/src/midiio/include/MidiInPort_unsupported.h @@ -0,0 +1,89 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Fri Jan 23 00:04:51 GMT-0800 1998 +// Last Modified: Fri Jan 23 00:04:58 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:42:59 PDT 1999 (added sysex capability) +// Filename: ...sig/code/control/MidiInPort/unsupported/MidiInPort_unsupported.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiInPort_unsupported.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// an unknown sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// This class is used when there is no MIDI input, so +// that MIDI programs can otherwise be compiled and run. +// This file can also serve as a template for creating +// an OS specific class for MIDI input. +// + +#ifndef _MIDIINPUT_UNSUPPORTED_H_INCLUDED +#define _MIDIINPUT_UNSUPPORTED_H_INCLUDED + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" + +class MidiInPort_unsupported { + public: + MidiInPort_unsupported (void); + MidiInPort_unsupported (int aPort, int autoOpen = 1); + ~MidiInPort_unsupported (); + + void clearSysex (int index) { } + void clearSysex (void) { } + int getSysexSize (int index) { return 0; } + uchar* getSysex (int buffer) { return NULL; } + int installSysex (unsigned char *&, int &) { return 0; } + int getBufferSize (void) { return 0; } + void close (void); + void close (int i) { close(); } + void closeAll (void); + MidiMessage extract (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + int getTrace (void); + void insert (const MidiMessage& aMessage); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + protected: + int port; // the port to which this object belongs + int trace; + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int numDevices; // number of input ports + static CircularBuffer* midiBuffer; // MIDI storage from ports + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array** sysexBuffers; // for MIDI sysex storage + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + +}; + + + +#endif /* _MIDIINPUT_UNSUPPORTED_H_INCLUDED */ + + + +// md5sum: ff5492fbd59a47e48e2c0ce06705add1 - MidiInPort_unsupported.h =css= 20030102 diff --git a/src/midiio/include/MidiInPort_visual.h b/src/midiio/include/MidiInPort_visual.h new file mode 100644 index 0000000..398a187 --- /dev/null +++ b/src/midiio/include/MidiInPort_visual.h @@ -0,0 +1,114 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 +// Last Modified: Mon Jan 12 20:05:27 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:29:51 PDT 1999 (added sysex capability) +// Filename: ...sig/code/control/MidiInPort/visual/MidiInPort_visual.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiInPort_visual.h +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// Windows 95/NT/98 specific MIDI input methods. +// as defined in winmm.lib. This class is inherited +// privately by the MidiInPort class. +// + +#ifndef _MIDIINPUT_VISUAL_H_INCLUDED +#define _MIDIINPUT_VISUAL_H_INCLUDED + + +#ifdef VISUAL + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +#include +#include + +#include "MidiMessage.h" +#include "CircularBuffer.h" +#include "Array.h" + +class MidiInPort_visual { + public: + MidiInPort_visual (void); + MidiInPort_visual (int aPort, int autoOpen = 1); + ~MidiInPort_visual (); + + void clearSysex (void); + void clearSysex (int buffer); + void close (void); + void closeAll (void); + MidiMessage extract (void); + int getBufferSize (void); + int getChannelOffset (void) const; + int getCount (void); + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + uchar* getSysex (int buffer); + int getSysexSize (int buffer); + int getTrace (void); + void insert (const MidiMessage& aMessage); + int installSysex (uchar* anArray, int aSize); + MidiMessage& message (int index); + int open (void); + void pause (void); + void setBufferSize (int aSize); + void setChannelOffset (int anOffset); + void setPort (int aPort); + int setTrace (int aState); + void toggleTrace (void); + void unpause (void); + + protected: + int port; // the port to which this object belongs + int trace; + + int installSysexPrivate (int port, uchar* anArray, int aSize); + void installSysexStuff (HMIDIIN dev, int port); + void uninstallSysexStuff (HMIDIIN dev, int port); + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int* inrunningQ; // for running open input port + static int numDevices; // number of input ports + static HMIDIIN* device; // Windoze MIDI-in device structure + static MIDIHDR** sysexDriverBuffer1; // for Windoze driver sysex buffers + static MIDIHDR** sysexDriverBuffer2; // for Windoze driver sysex buffers + static int* sysexDBnumber; // for Windoze driver sysex buffers + static HANDLE* hMutex; // mutual exclusive + static CircularBuffer* midiBuffer; // MIDI storage from ports + static int channelOffset; // channel offset from either 0 or 1. + // not being used right now. + static int* sysexWriteBuffer; // for MIDI sysex write location + static Array** sysexBuffers;// for MIDI sysex storage + static int* sysexStatus; // tracing multiple MIM_LONGDATA messgs + + private: + void deinitialize (void); + void initialize (void); + void releaseMutex (void); + void setPortStatus (int aStatus); + void waitForMutex (void); + + + friend void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus, + DWORD instancePtr, DWORD midiMessage, DWORD timestamp); +}; + + +// This is the command which is called by the driver when there is +// MIDI data being received from the MIDI input port: + void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus, + DWORD instancePtr, DWORD midiMessage, DWORD timestamp); + + +#endif /* VISUAL */ +#endif /* _MIDIINPUT_VISUAL_H_INCLUDED */ + + + +// md5sum: d5aee7a88c4a054b3e2d4d40622fdc42 - MidiInPort_visual.h =css= 20030102 diff --git a/src/midiio/include/MidiInput.h b/src/midiio/include/MidiInput.h new file mode 100644 index 0000000..4425f75 --- /dev/null +++ b/src/midiio/include/MidiInput.h @@ -0,0 +1,53 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 18 December 1997 +// Last Modified: Sun Jan 25 15:27:02 GMT-0800 1998 +// Last Modified: Thu Apr 20 16:23:24 PDT 2000 (added scale function) +// Filename: ...sig/code/control/MidiInput/MidiInput.h +// Web Address: http://sig.sapp.org/include/sig/MidiInput.h +// Syntax: C++ +// +// Description: A higher-level MIDI input interface than the +// MidiInPort class. Can be used to allow multiple +// objects to share a single MIDI input stream, or +// to fake a MIDI input connection. +// + +#ifndef _MIDIINPUT_H_INCLUDED +#define _MIDIINPUT_H_INCLUDED + + +#include "MidiInPort.h" + + +class MidiInput : public MidiInPort { + public: + MidiInput (void); + MidiInput (int aPort, int autoOpen = 1); + ~MidiInput (); + + int getBufferSize (void); + int getCount (void); + MidiMessage extract (void); + void insert (const MidiMessage& aMessage); + int isOrphan (void) const; + void makeOrphanBuffer (int aSize = 1024); + void removeOrphanBuffer(void); + void setBufferSize (int aSize); + + int scale (int value, int min, int max); + double fscale (int value, double min, double max); + int scale14 (int value, int min, int max); + double fscale14 (int value, double min, double max); + + protected: + CircularBuffer* orphanBuffer; + +}; + + +#endif /* _MIDIINPUT_H_INCLUDED */ + + + +// md5sum: 73972cc29d7bcf0fba136b098c0419a0 - MidiInput.h =css= 20030102 diff --git a/src/midiio/include/MidiMessage.h b/src/midiio/include/MidiMessage.h new file mode 100644 index 0000000..e4b59ba --- /dev/null +++ b/src/midiio/include/MidiMessage.h @@ -0,0 +1,78 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: 19 December 1997 +// Last Modified: Fri Jan 23 00:21:24 GMT-0800 1998 +// Last Modified: Sun Sep 20 20:30:53 PDT 1998 +// Last Modified: Mon Oct 15 14:29:12 PDT 2001 (added is_note functions) +// Filename: ...sig/include/sigInfo/MidiMessage.h +// Web Address: http://sig.sapp.org/include/sigInfo/MidiMessage.h +// Syntax: C++ +// +// Description: A structure for handling MIDI input messages. +// This class stores a time stamp plus up to +// four MIDI message bytes. System Exclusive messages +// are stored in a separate array in the MidiInPort +// class, and their storage index is passed to the +// user through a MIDI message for later extraction +// of the full sysex message. +// + +#ifndef _MIDIMESSAGE_H_INCLUDED +#define _MIDIMESSAGE_H_INCLUDED + +#include + +typedef unsigned char uchar; +typedef unsigned long ulong; + +class MidiMessage { + public: + ulong time; // timestamp + ulong data; // MIDI command and parameters + + MidiMessage (void); + MidiMessage (int aCommand, int aP1, int aP2, + int aTime = 0); + MidiMessage (const MidiMessage& aMessage); + ~MidiMessage (); + + uchar& command (void); + MidiMessage& operator= (const MidiMessage& aMessage); + uchar& operator[] (int index); + uchar& p0 (void); + uchar& p1 (void); + uchar& p2 (void); + uchar& p3 (void); + int getArgCount (void) const; + int getParameterCount (void) const; + + uchar getCommand (void) const; + uchar getP0 (void) const; + uchar getP1 (void) const; + uchar getP2 (void) const; + uchar getP3 (void) const; + + void setCommand (uchar aCommand); + void setData (uchar aCommand, uchar aP1 = 0, + uchar aP2 = 0, uchar aP3 = 0); + void setP0 (uchar aP0); + void setP1 (uchar aP1); + void setP2 (uchar aP2); + void setP3 (uchar aP3); + + int is_note (void); + int is_note_on (void); + int is_note_off (void); + +}; + + +std::ostream& operator<<(std::ostream& out, MidiMessage& aMessage); + + +#endif /* _MIDIMESSAGE_H_INCLUDED */ + + + +// md5sum: 4738e957fb8a233f6dbaeebda490e6a4 - MidiMessage.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort.h b/src/midiio/include/MidiOutPort.h new file mode 100644 index 0000000..0287dfd --- /dev/null +++ b/src/midiio/include/MidiOutPort.h @@ -0,0 +1,92 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Dec 28 15:04:24 GMT-0800 1997 +// Last Modified: Fri Jan 23 10:56:18 GMT-0800 1998 +// Last Modified: Sat Nov 7 16:15:54 PST 1998 +// Last Modified: Tue May 23 23:08:44 PDT 2000 (oss/alsa selection added) +// Last Modified: Mon Jun 19 10:32:11 PDT 2000 (oss/alsa define fix) +// Filename: ...sig/code/control/MidiOutPort/MidiOutPort.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort.h +// Syntax: C++ +// +// Description: Operating-System independent interface for +// basic MIDI output capabilities. Privately +// inherits the operating-system specific class +// for MIDI output. +// + +#ifndef _MIDIOUTPORT_H_INCLUDED +#define _MIDIOUTPORT_H_INCLUDED + + +#ifdef VISUAL + #define MIDIOUTPORT MidiOutPort_visual + #include "MidiOutPort_visual.h" +#elif defined(LINUX) && defined(ALSA) && defined(OSS) + #define MIDIOUTPORT MidiOutPort_linux + #include "MidiOutPort_linux.h" +#elif defined(LINUX) && defined(ALSA) && !defined(OSS) + #define MIDIOUTPORT MidiOutPort_alsa + #include "MidiOutPort_alsa.h" +#elif defined (LINUX) && defined(OSS) && !defined(ALSA) + #define MIDIOUTPORT MidiOutPort_oss + #include "MidiOutPort_oss.h" +#elif defined(LINUX) + #define MIDIOUTPORT MidiOutPort_oss + #include "MidiOutPort_oss.h" +#else + #define MIDIOUTPORT MidiOutPort_unsupported + #include "MidiOutPort_unsupported.h" +#endif + + +class MidiOutPort : protected MIDIOUTPORT { + public: + MidiOutPort (void) : MIDIOUTPORT() {} + MidiOutPort (int aPort, int autoOpen = 1) : + MIDIOUTPORT(aPort, autoOpen) {} + ~MidiOutPort() { } + + void close(void) { MIDIOUTPORT::close(); } + void closeAll(void) { MIDIOUTPORT::closeAll(); } + int getChannelOffset(void) const { + return MIDIOUTPORT::getChannelOffset(); } + const char* getName(void) { return MIDIOUTPORT::getName(); } + static const char* getName(int i) { return MIDIOUTPORT::getName(i); } + static int getNumPorts(void) { return MIDIOUTPORT::getNumPorts(); } + int getPort(void) { return MIDIOUTPORT::getPort(); } + int getPortStatus(void) { + return MIDIOUTPORT::getPortStatus(); } + int getTrace(void) { + return MIDIOUTPORT::getTrace(); } + int open(void) { return MIDIOUTPORT::open(); } + int rawsend(int command, int p1, int p2) { + return MIDIOUTPORT::rawsend(command, p1, p2); } + int rawsend(int command, int p1) { + return MIDIOUTPORT::rawsend(command, p1); } + int rawsend(int command) { + return MIDIOUTPORT::rawsend(command); } + int rawsend(uchar* array, int size) { + return MIDIOUTPORT::rawsend(array, size); } + void setAndOpenPort(int aPort) { setPort(aPort); open(); } +// void setChannelOffset(int aChannel) { +// MIDIOUTPORT::setChannelOffset(aChannel); } + void setPort(int aPort) { MIDIOUTPORT::setPort(aPort); } + int setTrace(int aState) { + return MIDIOUTPORT::setTrace(aState); } + int sysex(uchar* array, int size) { + return MIDIOUTPORT::sysex(array, size); } + void toggleTrace(void) { MIDIOUTPORT::toggleTrace(); } + MidiOutPort& operator=(MidiOutPort& other) { + setPort(other.getPort()); + if (other.getPortStatus()) { open(); } + return *this; } +}; + + + + +#endif /* _MIDIOUTPORT_H_INCLUDED */ + + +// md5sum: 2f7b8aa8ef705eab57179b626ce1d62d - MidiOutPort.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_alsa.h b/src/midiio/include/MidiOutPort_alsa.h new file mode 100644 index 0000000..34139a3 --- /dev/null +++ b/src/midiio/include/MidiOutPort_alsa.h @@ -0,0 +1,79 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed May 10 16:22:00 PDT 2000 +// Last Modified: Sun May 14 20:43:44 PDT 2000 +// Last Modified: Sat Nov 2 20:39:01 PST 2002 (added ALSA def) +// Filename: ...sig/maint/code/control/MidiOutPort/linux/MidiOutPort_alsa.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_alsa.h +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// OSS sound drivers. Privately inherited by the +// MidiOutPort class. +// + +#ifndef _MIDIOUTPORT_ALSA_H_INCLUDED +#define _MIDIOUTPORT_ALSA_H_INCLUDED + +#ifdef LINUX +#ifdef ALSA + +#include "Sequencer_alsa.h" +#include + +typedef unsigned char uchar; + + +class MidiOutPort_alsa : public Sequencer_alsa { + public: + MidiOutPort_alsa (void); + MidiOutPort_alsa (int aPort, int autoOpen = 1); + ~MidiOutPort_alsa (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + int getPort (void); + static int getNumPorts (void); + int getPortStatus (void); + int getTrace (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int numDevices; // number of output ports + static int* trace; // for printing messages to output + static std::ostream* tracedisplay; // for printing trace messages + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1. + // not being used right now. +}; + + + +#endif /* ALSA */ +#endif /* LINUX */ +#endif /* _MIDIOUTPUT_ALSA_H_INCLUDED */ + + +// md5sum: 5b7648c7b493df7cb0d1fae3bbb8be24 - MidiOutPort_alsa.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_linux.h b/src/midiio/include/MidiOutPort_linux.h new file mode 100644 index 0000000..a02dc22 --- /dev/null +++ b/src/midiio/include/MidiOutPort_linux.h @@ -0,0 +1,80 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed May 10 16:03:52 PDT 2000 +// Last Modified: Thu May 18 23:37:17 PDT 2000 +// Last Modified: Sat Nov 2 20:40:01 PST 2002 (added ALSA OSS def) +// Filename: ...sig/code/control/MidiOutPort_linux/MidiOutPort_linux.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_linux.h +// Syntax: C++ +// +// Description: Linux MIDI output class which detects which +// type of MIDI drivers are available: either +// ALSA or OSS. +// + +#ifndef _MIDIOUTPORT_LINUX_H_INCLUDED +#define _MIDIOUTPORT_LINUX_H_INCLUDED + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#include "MidiOutPort_oss.h" +#include "MidiOutPort_alsa.h" +#include "MidiOutPort_unsupported.h" + +#define UNKNOWN_MIDI_SELECT 0 /* use dummy MIDI output */ +#define OSS_MIDI_SELECT 1 /* use OSS MIDI output */ +#define ALSA_MIDI_SELECT 2 /* use ALSA MIDI output */ + +class MidiOutPort_linux { + public: + MidiOutPort_linux (void); + MidiOutPort_linux (int aPort, int autoOpen = 1); + ~MidiOutPort_linux (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + static int getNumPorts (void); + int getPort (void); + int getPortStatus (void); + int getTrace (void); + int open (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + void setAndOpenPort (int aPort); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + static int getSelect (void); + static int selectOSS (void); + static int selectALSA (void); + static int selectUnknown (void); + + private: + static int current; // the type of MIDI out selected + static int alsaQ; // boolean for if ALSA is present + static int ossQ; // boolean for if OSS is present + + static int objectCount; + static MidiOutPort_oss *oss_output; + static MidiOutPort_alsa *alsa_output; + static MidiOutPort_unsupported *unknown_output; + + void determineDrivers (void); +}; + +#endif /* ALSA and OSS */ +#endif /* LINUX */ + +#endif /* _MIDIOUTPORT_LINUX_H_INCLUDED */ + + +// md5sum: c80f9f47c45a6d4a20b6549743cae9fb - MidiOutPort_linux.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_oss.h b/src/midiio/include/MidiOutPort_oss.h new file mode 100644 index 0000000..22cf32d --- /dev/null +++ b/src/midiio/include/MidiOutPort_oss.h @@ -0,0 +1,75 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Fri Dec 18 19:15:00 PST 1998 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/maint/code/control/MidiOutPort/linux/MidiOutPort_oss.h +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_oss.h +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// OSS sound drivers. Privately inherited by the +// MidiOutPort class. +// + +#ifndef _MIDIOUTPORT_OSS_H_INCLUDED +#define _MIDIOUTPORT_OSS_H_INCLUDED + +#ifdef LINUX + +#include "Sequencer_oss.h" + +typedef unsigned char uchar; + + +class MidiOutPort_oss : public Sequencer_oss { + public: + MidiOutPort_oss (void); + MidiOutPort_oss (int aPort, int autoOpen = 1); + ~MidiOutPort_oss (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + int getPort (void); + static int getNumPorts (void); + int getPortStatus (void); + int getTrace (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int numDevices; // number of output ports + static int* trace; // for printing messages to output + static std::ostream* tracedisplay; // for printing trace messages + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1. + // not being used right now. +}; + + + +#endif /* LINUX */ +#endif /* _MIDIOUTPUT_OSS_H_INCLUDED */ + + +// md5sum: f60183e23c49741e93d9b965bbe9a6d8 - MidiOutPort_oss.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_unsupported.h b/src/midiio/include/MidiOutPort_unsupported.h new file mode 100644 index 0000000..a5e8c35 --- /dev/null +++ b/src/midiio/include/MidiOutPort_unsupported.h @@ -0,0 +1,71 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Mon Jan 12 21:36:26 GMT-0800 1998 +// Last Modified: Mon Jan 12 21:36:31 GMT-0800 1998 +// Filename: ...sig/code/control/MidiOutPort/unsupported/MidiOutPort_unsupported.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiOutPort_unsupported.h +// Syntax: C++ +// +// Description: Operating-System specific interface for basic MIDI output +// capabilities in an unknown operating system. Privately +// inherited by the MidiOutPort class. Used for compiling +// and running MIDI programs on a computer with no +// MIDI output. +// + +#ifndef _MIDIOUTPUT_UNSUPPORTED_H_INCLUDED +#define _MIDIOUTPUT_UNSUPPORTED_H_INCLUDED + +typedef unsigned char uchar; + +class MidiOutPort_unsupported { + public: + MidiOutPort_unsupported (void); + MidiOutPort_unsupported (int aPort, int autoOpen = 1); + ~MidiOutPort_unsupported (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void) const; + const char* getName (int i) const; + int getPort (void) const; + int getNumPorts (void) const; + int getPortStatus (void) const; + int getTrace (void) const; + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + int trace; // for printing out midi messages to standard output + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int numDevices; // number of output ports + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1 + // not being used right now. +}; + + + +#endif /* _MIDIOUTPUT_UNSUPPORTED_H_INCLUDED */ + + + +// md5sum: e244688a99d220addc7b1c6f6f6a8022 - MidiOutPort_unsupported.h =css= 20030102 diff --git a/src/midiio/include/MidiOutPort_visual.h b/src/midiio/include/MidiOutPort_visual.h new file mode 100644 index 0000000..d6a3984 --- /dev/null +++ b/src/midiio/include/MidiOutPort_visual.h @@ -0,0 +1,75 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 +// Last Modified: Mon Jan 12 20:05:27 GMT-0800 1998 +// Filename: ...sig/code/control/MidiOutPort/visual/MidiOutPort_visual.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiOutPort_visual.h +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Windows 95/NT/98 +// using winmm.lib. Privately inherited by the +// MidiOutPort class. +// + +#ifndef _MIDIOUTPUT_VISUAL_H_INCLUDED +#define _MIDIOUTPUT_VISUAL_H_INCLUDED + +#ifdef VISUAL + +typedef unsigned char uchar; + +#include +#include + +class MidiOutPort_visual { + public: + MidiOutPort_visual (void); + MidiOutPort_visual (int aPort, int autoOpen = 1); + ~MidiOutPort_visual (); + + void close (void); + void closeAll (void); + int getChannelOffset (void) const; + const char* getName (void); + static const char* getName (int i); + int getPort (void); + static int getNumPorts (void); + int getPortStatus (void); + int getTrace (void); + int rawsend (int command, int p1, int p2); + int rawsend (int command, int p1); + int rawsend (int command); + int rawsend (uchar* array, int size); + int open (void); + void setChannelOffset (int aChannel); + void setPort (int aPort); + int setTrace (int aState); + int sysex (uchar* array, int size); + void toggleTrace (void); + + protected: + int port; // the port to which this object belongs + int trace; // for printing out Midi messages to standard output + + static int objectCount; // num of similar objects in existence + static int* portObjectCount; // objects connected to particular port + static int* openQ; // for open/close status of port + static int numDevices; // number of output ports + static HMIDIOUT* device; // Windoze midi out device structure + + private: + void deinitialize (void); + void initialize (void); + void setPortStatus (int aStatus); + + static int channelOffset; // channel offset, either 0 or 1. + // not being used right now. +}; + + +#endif /* VISUAL */ +#endif /* _MIDIOUTPUT_VISUAL_H_INCLUDED */ + + +// md5sum: 47799e340effa57676be8a3943cabb70 - MidiOutPort_visual.h =css= 20030102 diff --git a/src/midiio/include/MidiOutput.h b/src/midiio/include/MidiOutput.h new file mode 100644 index 0000000..d424816 --- /dev/null +++ b/src/midiio/include/MidiOutput.h @@ -0,0 +1,140 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 18 December 1997 +// Last Modified: Mon Jan 26 23:53:05 GMT-0800 1998 +// Last Modified: Sat Jan 30 14:00:29 PST 1999 +// Last Modified: Sun Jul 18 18:52:42 PDT 1999 (added RPN functions) +// Filename: ...sig/maint/code/control/MidiOutput/MidiOutput.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiOutput.h +// Syntax: C++ +// +// Description: The MIDI output interface for MIDI synthesizers/equipment +// which has many convienience functions defined for +// various types of MIDI output. +// + +#ifndef _MIDIOUTPUT_H_INCLUDED +#define _MIDIOUTPUT_H_INCLUDED + +#include "MidiOutPort.h" +#include "FileIO.h" +#include "SigTimer.h" +#include "Array.h" + + +class MidiOutput : public MidiOutPort { + public: + MidiOutput (void); + MidiOutput (int aPort, int autoOpen = 1); + ~MidiOutput (); + + // Basic user MIDI output commands: + int cont (int channel, int controller, int data); + int off (int channel, int keynum, int releaseVelocity); + int pc (int channel, int timbre); + int play (int channel, int keynum, int velocity); + int pw (int channel, int mostByte, int leastByte); + int pw (int channel, int tuningData); + int pw (int channel, double tuningData); + void recordStart (char *filename, int format); + void recordStop (void); + void reset (void); + int send (int command, int p1, int p2); + int send (int command, int p1); + int send (int command); + void silence (int aChannel = -1); + void sustain (int channel, int status); + int sysex (char* data, int length); + int sysex (uchar* data, int length); + + protected: + int outputRecordQ; // boolean for recording + int outputRecordType; // what form to record MIDI data in + int lastFlushTime; // for recording midi data + FileIO outputRecordFile; // file for recording midi data + static SigTimer timer; // for recording midi data + static Array* rpn_lsb_status; // for RPN messages + static Array* rpn_msb_status; // for RPN messages + static int objectCount; // for RPN messages + + void deinitializeRPN (void); + void initializeRPN (void); + void writeOutputAscii (int channel, int p1, int p2); + void writeOutputBinary (int channel, int p1, int p2); + void writeOutputMidifile(int channel, int p1, int p2); + + public: // RPN controller functions + int NRPN (int channel, int nrpn_msb, int nrpn_lsb, + int data_msb, int data_lsb); + int NRPN (int channel, int nrpn_msb, int nrpn_lsb, + int data_msb); + int NRPN (int channel, int nrpn_msb, int nrpn_lsb, + double data); + int NRPN_null (int channel); + int NRPN_attack (int channel, double value); + int NRPN_attack (int channel, int value); + int NRPN_decay (int channel, double value); + int NRPN_decay (int channel, int value); + int NRPN_drumAttack (int drum, double value); + int NRPN_drumAttack (int drum, int value); + int NRPN_drumChorus (int drum, double value); + int NRPN_drumChorus (int drum, int value); + int NRPN_drumDecay (int drum, double value); + int NRPN_drumDecay (int drum, int value); + int NRPN_drumLevel (int drum, double value); + int NRPN_drumLevel (int drum, int value); + int NRPN_drumPan (int drum, double value); + int NRPN_drumPan (int drum, int value); + int NRPN_drumPitch (int drum, double value); + int NRPN_drumPitch (int drum, int value); + int NRPN_drumFilterCutoff (int drum, double value); + int NRPN_drumFilterCutoff (int drum, int value); + int NRPN_drumFilterResonance(int drum, double value); + int NRPN_drumFilterResonance(int drum, int value); + int NRPN_drumReverb (int drum, double value); + int NRPN_drumReverb (int drum, int value); + int NRPN_drumVariation (int drum, double value); + int NRPN_drumVariation (int drum, int value); + int NRPN_filterCutoff (int channel, double value); + int NRPN_filterCutoff (int channel, int value); + int NRPN_release (int channel, double value); + int NRPN_release (int channel, int value); + int NRPN_vibratoDelay (int channel, double value); + int NRPN_vibratoDelay (int channel, int value); + int NRPN_vibratoDepth (int channel, double value); + int NRPN_vibratoDepth (int channel, int value); + int NRPN_vibratoRate (int channel, double value); + int NRPN_vibratoRate (int channel, int value); + + int RPN (int channel, int rpn_msb, int rpn_lsb, + int data_msb, int data_lsb); + int RPN (int channel, int rpn_msb, int rpn_lsb, + int data_msb); + int RPN (int channel, int rpn_msb, int rpn_lsb, + double data); + int RPN_null (void); + int RPN_null (int channel); + int pbRange (int channel, int steps); + int tuneFine (int channel, int cents); + int fineTune (int channel, int cents); + int tuneCoarse (int channel, int steps); + int coarseTune (int channel, int steps); + int tuningProgram (int channel, int program); + int tuningBank (int channel, int bank); + +}; + + +#endif /* _MIDIOUTPUT_H_INCLUDED */ + +// Brief description of MidiOutput public member functions: +// +// send: sends a MIDI command to the MIDI output with up to two parameters +// play: sends a playnote command to the MIDI output +// pc: Patch Change. changes the timbre (instrument) on the given channel +// cont: sends a CONTinuous CONTroller MIDI command +// sysex: sends a system exclusive command to the MIDI output +// + + +// md5sum: 12ee02c32563ae219aaa8c7599de55db - MidiOutput.h =css= 20030102 diff --git a/src/midiio/include/MidiPort.h b/src/midiio/include/MidiPort.h new file mode 100644 index 0000000..834877e --- /dev/null +++ b/src/midiio/include/MidiPort.h @@ -0,0 +1,49 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 21 December 1997 +// Last Modified: Fri Jan 23 10:21:25 GMT-0800 1998 +// Filename: .../sig/code/control/MidiPort/MidiPort.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/MidiPort.h +// Syntax: C++ +// +// Description: A unified object that handles basic MIDI input and output. +// Derived from the MidiInPort and MidiOutPort classes. +// + +#ifndef _MIDIPORT_H_INCLUDED +#define _MIDIPORT_H_INCLUDED + + +#include "MidiInPort.h" +#include "MidiOutPort.h" + + +class MidiPort : public MidiOutPort, public MidiInPort { + public: + MidiPort (void); + MidiPort (int outputPort, int inputPort); + ~MidiPort (); + + int getChannelInOffset (void) const; + int getChannelOutOffset (void) const; + int getInputPort (void); + int getInputTrace (void); + int getOutputPort (void); + int getOutputTrace (void); + void setChannelOffset (int anOffset); + void setInputPort (int aPort); + int setInputTrace (int aState); + void setOutputPort (int aPort); + int setOutputTrace (int aState); + void toggleInputTrace (void); + void toggleOutputTrace (void); + +}; + + + +#endif /* _MIDIPORT_H_INCLUDED */ + + + +// md5sum: 84d8155528b06c9aa902e8f06649385f - MidiPort.h =css= 20030102 diff --git a/src/midiio/include/Options.h b/src/midiio/include/Options.h new file mode 100644 index 0000000..71754fb --- /dev/null +++ b/src/midiio/include/Options.h @@ -0,0 +1,106 @@ +// +// Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Fri Jan 15 07:24:00 PST 1999 +// Last Modified: Sat Mar 27 18:17:59 PST 1999 +// Last Modified: Thu Apr 13 14:02:52 PDT 2000 (added 2nd define function) +// Last Modified: Fri May 5 17:57:50 PDT 2000 (added --options suppression) +// Filename: ...sig/maint/code/base/Options/Options.h +// Web Address: http://sig.sapp.org/include/sigBase/Options.h +// Documentation: http://sig.sapp.org/doc/classes/Options +// Syntax: C++ +// +// Description: Handles command-line options in a graceful manner. +// + +#ifndef _OPTIONS_H_INCLUDED +#define _OPTIONS_H_INCLUDED + +#include "Array.h" + +class option_list; +class option_register; + + +class Options { + public: + Options (void); + Options (int argc, char** argv); + ~Options (); + + int argc (void) const; + char** argv (void) const; + void define (const char* aDefinition); + void define (const char* aDefinition, + const char* description); + char* getArg (int index); + char* getArgument (int index); + int getArgCount (void); + int getArgumentCount (void); + int getBoolean (const char* optionName); + const char* getCommand (void); + const char* getCommandLine (void); + const char* getString (void); + const char* getDefinition (const char* optionName); + double getDouble (const char* optionName); + char getFlag (void); + float getFloat (const char* optionName); + int getInt (const char* optionName); + int getInteger (const char* optionName); + const char* getString (const char* optionName); + char getType (const char* optionName); + int optionsArg (void); + void print (void); + void process (int error_check = 1, int suppress = 0); + void process (int argc, char** argv, + int error_check = 1, + int suppress = 0); + void reset (void); + void verify (int argc, char** argv, + int error_check = 1, + int suppress = 0); + void verify (int error_check = 1, + int suppress = 0); + void setFlag (char aFlag); + void setModified (const char* optionName, + const char* optionValue); + void setOptions (int argc, char** argv); + + protected: + int options_error_check; // for verify command + int gargc; + char** gargv; + char* commandString; + char optionFlag; + Array argument; + Array optionRegister; + Array optionList; + int processedQ; + int sortedQ; + int suppressQ; // prevent the --options option + int optionsArgument; // indicates --options present + + int getRegIndex (const char* optionName); + int optionQ (const char* aString, int& argp); + void sortOptionNames (void); + int storeOption (int gargp, int& position, + int& running); + +}; + +#define OPTION_BOOLEAN_TYPE 'b' +#define OPTION_CHAR_TYPE 'c' +#define OPTION_DOUBLE_TYPE 'd' +#define OPTION_FLOAT_TYPE 'f' +#define OPTION_INT_TYPE 'i' +#define OPTION_STRING_TYPE 's' +#define OPTION_UNKNOWN_TYPE 'x' + + + +#endif /* _OPTIONS_H_INCLUDED */ + + + +// md5sum: c59d297a8081cb48f61b534484819f48 - Options.h =css= 20030102 diff --git a/src/midiio/include/Options_private.h b/src/midiio/include/Options_private.h new file mode 100644 index 0000000..8349d55 --- /dev/null +++ b/src/midiio/include/Options_private.h @@ -0,0 +1,73 @@ +// +// Copyright 1998-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sun Jan 10 05:44:48 PST 1999 +// Filename: ...sig/maint/code/base/Options/Options_private.h +// Web Address: http://sig.sapp.org/include/sigBase/Options_private.h +// Syntax: C++ +// +// Description: A private function for use in the Options class. +// + +#ifndef _OPTIONS_PRIVATE_H_INCLUDED +#define _OPTIONS_PRIVATE_H_INCLUDED + + +class option_register { + public: + option_register (void); + option_register (const char* aDefinition, char aType, + const char* aDefaultOption, + const char* aModifiedOption); + ~option_register (); + void clearModified (void); + const char* getDefinition (void); + const char* getDefault (void); + const char* getOption (void); + const char* getModified (void); + int getModifiedQ (void); + char getType (void); + void reset (void); + void setDefault (const char* aString); + void setDefinition (const char* aString); + void setModified (const char* aString); + void setType (char aType); + + protected: + char* definition; + char* defaultOption; + char* modifiedOption; + char type; + +}; + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + + +class option_list { + public: + option_list (void); + option_list (const char* optionName, int anIndex); + ~option_list (); + + int getIndex (void); + const char* getName (void); + void setName (const char* aString); + void setIndex (int anIndex); + + protected: + char* name; + int index; + +}; + + + +#endif /* _OPTIONS_PRIVATE_H_INCLUDED */ + + + +// md5sum: b440ad2158e9921d0e31463a8c3e1ae0 - Options_private.h =css= 20030102 diff --git a/src/midiio/include/Sequencer_alsa.h b/src/midiio/include/Sequencer_alsa.h new file mode 100644 index 0000000..3227f5e --- /dev/null +++ b/src/midiio/include/Sequencer_alsa.h @@ -0,0 +1,139 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Thu May 11 21:06:21 PDT 2000 +// Last Modified: Sat Oct 13 14:50:04 PDT 2001 (updated for ALSA 0.9 interface) +// Filename: ...sig/maint/code/control/MidiOutPort/Sequencer_alsa.h +// Web Address: http://sig.sapp.org/include/sig/Sequencer_alsa.h +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux ALSA midi device /dev/snd/midiXX. This class +// is inherited by the classes MidiInPort_alsa and +// MidiOutPort_alsa. +// +// to get information of status a alsa hardware & software +// cat /proc/asound/version +// cat /proc/asound/devices +// cat /proc/asound/card0/midi0 +// + +#ifndef _SEQUENCER_ALSA_H_INCLUDED +#define _SEQUENCER_ALSA_H_INCLUDED + +#include + +#ifdef ALSA + +#include +#include "Collection.h" + +#define MIDI_EXTERNAL (1) +#define MIDI_INTERNAL (2) + +typedef unsigned char uchar; + + +class Sequencer_alsa { + public: + Sequencer_alsa (int autoOpen = 1); + ~Sequencer_alsa (); + + void close (void); + void closeInput (int index); + void closeOutput (int index); + void displayInputs (std::ostream& out = std::cout, + char* initial = "\t"); + void displayOutputs (std::ostream& out = std::cout, + char* initial = "\t"); + static const char* getInputName (int aDevice); + static const char* getOutputName (int aDevice); + static int getNumInputs (void); + static int getNumOutputs (void); + int is_open (int mode, int index); + int is_open_in (int index); + int is_open_out (int index); + int open (int direction, int index); + int openInput (int index); + int openOutput (int index); + void read (int dev, uchar* buf, int count); + void rebuildInfoDatabase (void); + int write (int aDevice, int aByte); + int write (int aDevice, uchar* bytes, int count); + int write (int aDevice, char* bytes, int count); + int write (int aDevice, int* bytes, int count); + + int getInCardValue (int aDevice) const; + int getOutCardValue (int aDevice) const; + protected: + static int class_count; // number of existing classes using + static int indevcount; // number of MIDI input devices + static int outdevcount; // number of MIDI output devices + static int initialized; // for starting buileinfodatabase + + static Collection Sequencer_alsa::rawmidi_in; + static Collection Sequencer_alsa::rawmidi_out; + static Collection Sequencer_alsa::midiincard; + static Collection Sequencer_alsa::midioutcard; + static Collection Sequencer_alsa::midiindevice; + static Collection Sequencer_alsa::midioutdevice; + static Collection Sequencer_alsa::midiinname; + static Collection Sequencer_alsa::midioutname; + + private: + static void buildInfoDatabase (void); + static void getPossibleMidiStreams(Collection& cards, + Collection& devices); + int getInDeviceValue (int aDevice) const; + int getInputType (int aDevice) const; + int getOutDeviceValue (int aDevice) const; + int getOutputType (int aDevice) const; + void removeInfoDatabase (void); + + + friend void *interpretMidiInputStreamPrivateALSA(void * x); + +}; + +#else /* ALSA is not defined */ + +typedef unsigned char uchar; + +class Sequencer_alsa { + public: + Sequencer_alsa (int autoOpen = 1) { } + ~Sequencer_alsa () { } + + void close (void) { }; + void displayInputs (std::ostream& out = std::cout, + char* initial = "\t") + { out << initial << "NONE\n"; } + void displayOutputs (std::ostream& out = std::cout, + char* initial = "\t") + { out << initial << "NONE\n"; } + static const char* getInputName (int aDevice) { return ""; } + static const char* getOutputName (int aDevice) { return ""; } + static int getNumInputs (void) { return 0; } + static int getNumOutputs (void) { return 0; } + int is_open (int mode, int index) { return 0; } + int is_open_in (int index) { return 0; } + int is_open_out (int index) { return 0; } + int open (void) { return 0; } + void read (int dev, uchar* buf, int count) { } + void rebuildInfoDatabase (void) { } + int write (int aDevice, int aByte) { return 0; } + int write (int aDevice, uchar* bytes, int count) { return 0; } + int write (int aDevice, char* bytes, int count) { return 0; } + int write (int aDevice, int* bytes, int count) { return 0; } + int getInCardValue (int aDevice) const { return 0; } + int getOutCardValue (int aDevice) const { return 0; } + +}; + + +#endif /* ALSA */ + + +#endif /* _SEQUENCER_ALSA_H_INCLUDED */ + + +// md5sum: 6147020b0646fca8245f653505308949 - Sequencer_alsa.h =css= 20030102 diff --git a/src/midiio/include/Sequencer_oss.h b/src/midiio/include/Sequencer_oss.h new file mode 100644 index 0000000..5f269a7 --- /dev/null +++ b/src/midiio/include/Sequencer_oss.h @@ -0,0 +1,92 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Jan 3 21:02:02 PST 1999 +// Last Modified: Sat Jan 30 14:11:18 PST 1999 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _oss to _oss) +// Filename: ...sig/maint/code/control/MidiOutPort/Sequencer_oss.h +// Web Address: http://sig.sapp.org/include/sig/Sequencer_oss.h +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux OSS midi device /dev/sequencer. This class +// is inherited by the classes MidiInPort_oss and +// MidiOutPort_oss. +// + +#ifndef _SEQUENCER_OSS_H_INCLUDED +#define _SEQUENCER_OSS_H_INCLUDED + +#include + +#define MIDI_EXTERNAL (1) +#define MIDI_INTERNAL (2) + +typedef unsigned char uchar; + + +class Sequencer_oss { + public: + Sequencer_oss (int autoOpen = 1); + ~Sequencer_oss (); + + void close (void); + void displayInputs (std::ostream& out = std::cout, + char* initial = "\t"); + void displayOutputs (std::ostream& out = std::cout, + char* initial = "\t"); + static int getNumInputs (void); + static int getNumOutputs (void); + static const char* getInputName (int aDevice); + static const char* getOutputName (int aDevice); + int is_open (void); + int open (void); + void read (uchar* buf, uchar* dev, int count); + void rawread (uchar* buf, int packetCount); + void rebuildInfoDatabase (void); + int write (int aDevice, int aByte); + int write (int aDevice, uchar* bytes, int count); + int write (int aDevice, char* bytes, int count); + int write (int aDevice, int* bytes, int count); + + protected: + static const char* sequencer; // name of sequencer device + static int sequencer_fd; // sequencer file descriptor + static int class_count; // number of existing classes using + static uchar midi_write_packet[4]; // for writing MIDI bytes out + static uchar midi_read_packet[4]; // for reading MIDI bytes out + static uchar synth_write_message[8]; // for writing to internal seq + static int indevcount; // number of MIDI input devices + static int outdevcount; // number of MIDI output devices + static char** indevnames; // MIDI input device names + static char** outdevnames; // MIDI output device names + static int* indevnum; // total number of MIDI inputs + static int* outdevnum; // total number of MIDI outputs + static int* indevtype; // 1 = External, 2 = Internal + static int* outdevtype; // 1 = External, 2 = Internal + static uchar synth_message_buffer[1024]; // hold bytes for synth dev + static int synth_message_buffer_count; // count of synth buffer + static int synth_message_bytes_expected; // expected count of synth + static int synth_message_curr_device; // for keeping track of dev + static int initialized; // for starting buileinfodatabase + + private: + static void buildInfoDatabase (void); + static int getFd (void); + int getInDeviceValue (int aDevice) const; + int getInputType (int aDevice) const; + int getOutDeviceValue (int aDevice) const; + int getOutputType (int aDevice) const; + void removeInfoDatabase (void); + void setFd (int anFd); + + int writeInternal(int aDevice, int aByte); + int transmitMessageToInternalSynth(void); + int transmitVoiceMessage(void); + int transmitCommonMessage(void); +}; + + +#endif /* _SEQUENCER_OSS_H_INCLUDED */ + + +// md5sum: 1df08cd946c609b9b42aadbc96b7a296 - Sequencer_oss.h =css= 20030102 diff --git a/src/midiio/include/SigTimer.h b/src/midiio/include/SigTimer.h new file mode 100644 index 0000000..e93345c --- /dev/null +++ b/src/midiio/include/SigTimer.h @@ -0,0 +1,104 @@ +// +// Programmer: Craig Stuart Sapp +// Thanks to: Erik Neuenschwander +// for Windows 95 assembly code for Pentium clock cycles. +// Ozgur Izmirli +// for concept of periodic timer. +// Creation Date: Mon Oct 13 11:34:57 GMT-0800 1997 +// Last Modified: Tue Feb 10 21:05:19 GMT-0800 1998 +// Last Modified: Sat Sep 19 15:56:48 PDT 1998 +// Last Modified: Mon Feb 22 04:44:25 PST 1999 +// Last Modified: Sun Nov 28 12:39:39 PST 1999 (added adjustPeriod()) +// Filename: .../sig/code/control/SigTimer/SigTimer.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/SigTimer.h +// Syntax: C++ +// +// Description: This class can only be used on Motorola Pentinum 75 Mhz +// chips or better because the timing information is +// extracted from the clock cycle count from a register +// on the CPU itself. This class will estimate the +// speed of the computer, but it would be better if there +// was a way of finding out the speed from some function. +// This class is used primarily for timing of MIDI input +// and output at a millisecond resolution. +// +// Interesting: http://www.datasilicon.nl/I786/timer_1.htm +// + +#ifndef _SIGTIMER_H_INCLUDED +#define _SIGTIMER_H_INCLUDED + + +#ifdef VISUAL + #include + typedef LONGLONG int64bits; +#else + typedef long long int int64bits; + #include /* for millisleep function */ +#endif + + +class SigTimer { + public: + SigTimer (void); + SigTimer (int aSpeed); + SigTimer (SigTimer& aTimer); + ~SigTimer (); + + void adjustPeriod (double periodDelta); + int expired (void) const; + double getPeriod (void) const; + double getPeriodCount (void) const; + double getTempo (void) const; + int getTicksPerSecond (void) const; + int getTime (void) const; + double getTimeInSeconds (void) const; + int getTimeInTicks (void) const; + void reset (void); + void setPeriod (double aPeriod); + void setTempo (double beatsPerMinute); + void setPeriodCount (double aCount); + void setTicksPerSecond (int aTickRate); + void start (void); + void sync (SigTimer& aTimer); + void update (void); + void update (int periodCount); + + // The following functions are semi-private. They do not have + // anything to do with timing themselves, but are a by-product + // of the timer implementation. They are useful, so they have + // been left public; however, they should be used judiciously. + static int getCpuSpeed (void); + static int measureCpuSpeed (int quantize = 0); + static void setCpuSpeed (int aSpeed); + + // the following function is hardware specific to Intel Pentium + // computers with a processor speed of at least 75 MHz. + // This function is the only non-portable function in this + // class, but everything else is based on it. + static int64bits clockCycles (void); + + protected: + static int64bits globalOffset; + static int cpuSpeed; + + int64bits offset; + int ticksPerSecond; + double period; + + // protected functions + double getFactor (void) const; + +}; + + +// The following function is mostly for Linux: +void millisleep(int milliseconds); +void millisleep(float milliseconds); + + +#endif /* _SIGTIMER_H_INCLUDED */ + + + +// md5sum: 601fa3caae4e3bacc4e6fb87f545c86b - SigTimer.h =css= 20030102 diff --git a/src/midiio/include/Voice.h b/src/midiio/include/Voice.h new file mode 100644 index 0000000..3cddf9f --- /dev/null +++ b/src/midiio/include/Voice.h @@ -0,0 +1,70 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Oct 11 18:21:46 PDT 1998 +// Last Modified: Sun Oct 11 18:33:04 PDT 1998 +// Filename: ...sig/maint/code/control/Voice/Voice.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/Voice.h +// Syntax: C++ +// +// Description: The Voice class is a MIDI output class which keeps +// track of the last note played in to it. If the last +// note was not turned off when a new note is played, +// then the old note will be turned off before the +// new note is played. +// + +#ifndef _VOICE_H_INCLUDED +#define _VOICE_H_INCLUDED + +#include "MidiOutput.h" + +class Voice : public MidiOutput { + public: + Voice (int aChannel); + Voice (const Voice& aVoice); + Voice (void); + ~Voice (); + + void cont (int controler, int data); + int getChan (void) const; + int getChannel (void) const; + int getKey (void) const; + int getKeynum (void) const; + int getOffTime (void) const; + int getOnTime (void) const; + int getVel (void) const; + int getVelocity (void) const; + void off (void); + void pc (int aTimbre); + void play (int aChannel, int aKeyno, int aVelocity); + void play (int aKeyno, int aVelocity); + void play (void); + void setChan (int aChannel); + void setChannel (int aChannel); + void setKey (int aKeyno); + void setKeynum (int aKeyno); + void setVel (int aVelocity); + void setVelocity (int aVelocity); + int status (void) const; + void sustain (int aStatus); + + protected: + int chan; // the current channel number + int key; // the current key number + int vel; // the current velocity value + + int onTime; // last note on message sent + int offTime; // last note off message sent + + int oldChan; // last channel played on + int oldKey; // last key to be played + int oldVel; // last velocity of last key + + static SigTimer timer; // for recording on/off times +}; + + +#endif /* _VOICE_H_INCLUDED */ + + +// md5sum: 8a5495ecc10d42be6b1832492e107723 - Voice.h =css= 20030102 diff --git a/src/midiio/include/gminstruments.h b/src/midiio/include/gminstruments.h new file mode 100644 index 0000000..0e567da --- /dev/null +++ b/src/midiio/include/gminstruments.h @@ -0,0 +1,251 @@ +// +// Copyright 1997-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp (from 18Dec1997) +// Creation Date: 26 December 1997 +// Last Modified: Tue Apr 18 11:38:28 PDT 2000 (put CH_X defines here) +// Filename: ...sig/include/sigInfo/gminstruments.h +// Web Address: http://sig.sapp.org/include/sigInfo/gminstruments.h +// Syntax: C +// +// Description: Defines names for instruments as arranged in General MIDI. +// + +#ifndef _GMINSTRUMENTS_H_INCLUDED +#define _GMINSTRUMENTS_H_INCLUDED + +#define CH_1 0 +#define CH_2 1 +#define CH_3 2 +#define CH_4 3 +#define CH_5 4 +#define CH_6 5 +#define CH_7 6 +#define CH_8 7 +#define CH_9 8 +#define CH_10 9 +#define CH_11 10 +#define CH_12 11 +#define CH_13 12 +#define CH_14 13 +#define CH_15 14 +#define CH_16 15 + +#define GM_PIANO(X) (0+(X)) +#define GM_ACOUSTIC_GRAND_PIANO (0) +#define GM_BRIGHT_ACOUSTIC_PIANO (1) +#define GM_ELECTRIC_GRAND_PIANO (1) +#define GM_HONKYTONK_PIANO (2) +#define GM_HONKY_TONK_PIANO (3) +#define GM_ELECTRIC_PIANO_1 (4) +#define GM_ELECTRIC_PIANO_2 (5) +#define GM_HARPSICHORD (6) +#define GM_CLAVI (7) + +#define GM_CHROMATIC(X) (8+(X)) +#define GM_CELESTA (8) +#define GM_GLOCKENSPIEL (9) +#define GM_MUSIC_BOX (10) +#define GM_VIBRAPHONE (11) +#define GM_MARIMBA (12) +#define GM_XYLOPHONE (13) +#define GM_TUBULAR_BELLS (14) +#define GM_DULCIMER (15) + +#define GM_ORGAN(X) (16+(X)) +#define GM_DRAWBAR_ORGAN (16) +#define GM_PERCUSSIVE_ORGAN (17) +#define GM_ROCK_ORGAN (18) +#define GM_CHURCH_ORGAN (19) +#define GM_REED_ORGAN (20) +#define GM_ACCORDION (21) +#define GM_HARMONICA (22) +#define GM_TANGO_ACCORDION (23) + +#define GM_GUITAR(X) (24+(X)) +#define GM_ACOUSTIC_GUITAR_NYLON (24) +#define GM_ACOUSTIC_GUITAR_STEEL (25) +#define GM_ELECTRIC_GUITAR_JAZZ (26) +#define GM_ELECTRIC_GUITAR_CLEAN (27) +#define GM_ELECTRIC_GUITAR_MUTED (28) +#define GM_OVERDRIVEN_GUITAR (29) +#define GM_DISTORTION_GUITAR (30) +#define GM_GUITAR_HARMONICS (31) + +#define GM_BASS(X) (32+(X)) +#define GM_ACOUSTIC_BASS (32) +#define GM_ELECTRIC_BASS_FINGER (33) +#define GM_ELECTRIC_BASS_PICK (34) +#define GM_FRETLESS_BASS (35) +#define GM_SLAP_BASS_1 (36) +#define GM_SLAP_BASS_2 (37) +#define GM_SYNTH_BASS_1 (38) +#define GM_SYNTH_BASS_2 (39) + +#define GM_STRINGS(X) (40+(X)) +#define GM_VIOLIN (40) +#define GM_VIOLA (41) +#define GM_CELLO (42) +#define GM_CONTRABASS (43) +#define GM_TREMOLO_STRINGS (44) +#define GM_PIZZACATO_STRINGS (45) +#define GM_ORCHESTRAL_HARP (46) +#define GM_TIMPANI (47) + +#define GM_ENSEMBLE(X) (48+(X)) +#define GM_STRING_ENSEMBLE_1 (48) +#define GM_STRING_ENSEMBLE_2 (49) +#define GM_SYNTHSTRINGS_1 (50) +#define GM_SYNTHSTRINGS_2 (51) +#define GM_CHOIR_AAHS (52) +#define GM_VOICE_OOHS (53) +#define GM_SYNTH_VOICE (54) +#define GM_ORCHESTRA_HIT (55) + +#define GM_BRASS(X) (56+(X)) +#define GM_TRUMPET (56) +#define GM_TROMBONE (57) +#define GM_TUBA (58) +#define GM_MUTED_TRUMPED (59) +#define GM_FRENCH_HORN (60) +#define GM_BRASS_SECTION (61) +#define GM_SYNTHBRASS_1 (62) +#define GM_SYNTHBRASS_2 (63) + +#define GM_REED(X) (64+(X)) +#define GM_SOPRANO_SAX (64) +#define GM_ALTO_SAX (65) +#define GM_TENOR_SAX (66) +#define GM_BARITONE_SAX (67) +#define GM_OBOE (68) +#define GM_ENGLISH_HORN (69) +#define GM_BASSOON (70) +#define GM_CLARINET (71) + +#define GM_PIPE(X) (72+(X)) +#define GM_PICCOLO (72) +#define GM_FLUTE (73) +#define GM_RECORDER (74) +#define GM_PAN_FLUTE (75) +#define GM_BLOWN_BOTTLE (76) +#define GM_SHAKUHACHI (77) +#define GM_WHISTLE (78) +#define GM_OCARINA (79) + +#define GM_LEAD(X) (80+(X)) +#define GM_LEAD_SQUARE (80) +#define GM_LEAD_SAWTOOTH (81) +#define GM_LEAD_CALLIOPE (82) +#define GM_LEAD_CHIFF (83) +#define GM_LEAD_CHARANG (84) +#define GM_LEAD_VOICE (85) +#define GM_LEAD_FIFTHS (86) +#define GM_LEAD_BASS (87) + +#define GM_PAD(X) (88+(X)) +#define GM_PAD_NEW_AGE (88) +#define GM_PAD_WARM (89) +#define GM_PAD_POLYSYNTH (90) +#define GM_PAD_CHOIR (91) +#define GM_PAD_BOWED (92) +#define GM_PAD_METALLIC (93) +#define GM_PAD_HALO (94) +#define GM_PAD_SWEEP (95) + +#define GM_FX(X) (96+(X)) +#define GM_FX_TRAIN (96) +#define GM_FX_SOUNDTRACK (97) +#define GM_FX_CRYSTAL (98) +#define GM_FX_ATMOSPHERE (99) +#define GM_FX_BRIGHTNESS (100) +#define GM_FX_GOBLINS (101) +#define GM_FX_ECHOES (102) +#define GM_FX_SCI_FI (103) + +#define GM_ETHNIC(X) (104+(X)) +#define GM_SITAR (104) +#define GM_BANJO (105) +#define GM_SHAMISEN (106) +#define GM_KOTO (107) +#define GM_KALIMBA (108) +#define GM_BAGPIPE (109) +#define GM_FIDDLE (110) +#define GM_SHANAI (111) + +#define GM_PERCUSSION(X) (112+(X)) +#define GM_TINKLE_BELL (112) +#define GM_AGOGO (113) +#define GM_STEEL_DRUMS (114) +#define GM_WOODBLOCKS (115) +#define GM_TAIKO_DRUM (116) +#define GM_MELODIC_DRUM (117) +#define GM_SYNTH_DRUM (118) +#define GM_REVERSE_CYMBAL (119) + +#define GM_SOUNDEFFECT(X) (120+(X)) +#define GM_GUITAR_FRET_NOISE (120) +#define GM_BREATH_NOISE (121) +#define GM_SEASHORE (122) +#define GM_BIRD_TWEET (123) +#define GM_TELEPHONE_RING (124) +#define GM_HELICOPTER (125) +#define GM_APPLAUSE (126) +#define GM_GUNSHOT (127) + +// +// Percussion instruments on channel 10 +// + +#define GM_ACOUSTIC_BASS_DRUM (35) +#define GM_BASS_DRUM_1 (36) +#define GM_SIDE_STICK (37) +#define GM_ACOUSTIC_SNARE (38) +#define GM_HAND_CLAP (39) +#define GM_ELECTRIC_SNARE (40) +#define GM_LOW_FLOOR_TOM (41) +#define GM_CLOSED_HI_HAT (42) +#define GM_HIGH_FLOOR_TOM (43) +#define GM_PEDAL_HI_HAT (44) +#define GM_LOW_TOM (45) +#define GM_OPEN_HI_HAT (46) +#define GM_LOW_MID_TOM (47) +#define GM_HIGH_MID_TOM (48) +#define GM_CRASH_CYMBAL_1 (49) +#define GM_HIGH_TOM (50) +#define GM_RIDE_CYMBAL_1 (51) +#define GM_CHINESE_CYMBAL (52) +#define GM_RIDE_BELL (53) +#define GM_TAMBOURINE (54) +#define GM_SPLASH_CYMBAL (55) +#define GM_COWBELL (56) +#define GM_CRASH_CYMBAL_2 (57) +#define GM_VIBRASLAP (58) +#define GM_RIDE_CYMBAL_2 (59) +#define GM_HI_BONGO (60) +#define GM_LOW_BONGO (61) +#define GM_MUTE_HI_CONGA (62) +#define GM_OPEN_HI_CONGA (63) +#define GM_LOW_CONGA (64) +#define GM_HIGH_TIMBALE (65) +#define GM_LOW_TIMBALE (66) +#define GM_HIGH_AGOGO (67) +#define GM_LOW_AGOGO (68) +#define GM_CABASA (69) +#define GM_MARACAS (70) +#define GM_SHORT_WHISTLE (71) +#define GM_LONG_WHISTLE (72) +#define GM_SHORT_GUIRO (73) +#define GM_LONG_GUIRO (74) +#define GM_CLAVES (75) +#define GM_HI_WOOD_BLOCK (76) +#define GM_LOW_WOOD_BLOCK (77) +#define GM_MUTE_CUICA (78) +#define GM_OPEN_CUICA (79) +#define GM_MUTE_TRIANGLE (80) +#define GM_OPEN_TRIANGLE (81) + + +#endif /* _GMINSTRUMENTS_H_INCLUDED */ + + + +// md5sum: 6299d04892a6899533b9164aa9e1a874 - gminstruments.h =css= 20030102 diff --git a/src/midiio/include/midichannels.h b/src/midiio/include/midichannels.h new file mode 100644 index 0000000..4526813 --- /dev/null +++ b/src/midiio/include/midichannels.h @@ -0,0 +1,42 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 21 December 1997 +// Last Modified: Wed Feb 11 22:49:59 GMT-0800 1998 +// Filename: ...sig/code/control/misc/midichannels.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/midichannels.h +// Syntax: C++ +// +// Description: Offset by 1 MIDI channel names. +// + +#ifndef _MIDICHANNELS_H_INCLUDED +#define _MIDICHANNELS_H_INCLUDED + +/* temporarily changed : + +// channel defines: offset from 0 +#define CH_1 (0x00) +#define CH_2 (0x01) +#define CH_3 (0x02) +#define CH_4 (0x03) +#define CH_5 (0x04) +#define CH_6 (0x05) +#define CH_7 (0x06) +#define CH_8 (0x07) +#define CH_9 (0x08) +#define CH_10 (0x09) +#define CH_11 (0x0a) +#define CH_12 (0x0b) +#define CH_13 (0x0c) +#define CH_14 (0x0d) +#define CH_15 (0x0e) +#define CH_16 (0x0f) + +*/ + +#endif /* _MIDICHANNELS_H_INCLUDED */ + + + + +// md5sum: 5267399f7ff90a6ea3ad2dc132afae3e - midichannels.h =css= 20030102 diff --git a/src/midiio/include/mididefines.h b/src/midiio/include/mididefines.h new file mode 100644 index 0000000..4161c2f --- /dev/null +++ b/src/midiio/include/mididefines.h @@ -0,0 +1,34 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 21 December 1997 +// Last Modified: Wed Feb 11 22:49:59 GMT-0800 1998 +// Filename: ...sig/code/control/misc/mididefines.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/mididefines.h +// Syntax: C++ +// +// Description: Collection of all of the MIDI convienience defines. +// + +#ifndef _MIDIDEFINES_H_INCLUDED +#define _MIDIDEFINES_H_INCLUDED + + +// include channel defines +#include "midichannels.h" + + +// include note name defines +#include "notenames.h" + + +// include General MIDI instrument names +#include "gminstruments.h" + + + +#endif /* _MIDIDEFINES_H_INCLUDED */ + + + + +// md5sum: 0f081c8e0b386a11e448b6088bfcd489 - mididefines.h =css= 20030102 diff --git a/src/midiio/include/midiiolib.h b/src/midiio/include/midiiolib.h new file mode 100644 index 0000000..17d0430 --- /dev/null +++ b/src/midiio/include/midiiolib.h @@ -0,0 +1,57 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sat Nov 2 20:20:24 PST 2002 +// Last Modified: Thu Jan 2 18:51:20 PST 2003 (changed name from midio.h) +// Filename: ...sig/code/misc/midiiolib.h +// Web Address: http://sig.sapp.org/include/sig/midiiolib.h +// Syntax: C++ +// +// Description: Includes all of the header files for using the midiio +// Library. +// + +#ifndef _MIDIIOLIB_H_INCLUDED +#define _MIDIIOLIB_H_INCLUDED + +#include "Array.h" +#include "CircularBuffer.h" +#include "Collection.h" +#include "FileIO.h" +#include "gminstruments.h" +#include "midichannels.h" +#include "mididefines.h" +#include "MidiFile.h" +#include "MidiFileWrite.h" +#include "MidiInPort_alsa05.h" +#include "MidiInPort_alsa.h" +#include "MidiInPort.h" +#include "MidiInPort_linux.h" +#include "MidiInPort_oss.h" +#include "MidiInPort_unsupported.h" +#include "MidiInPort_visual.h" +#include "MidiInput.h" +#include "MidiIO.h" +#include "MidiMessage.h" +#include "MidiOutPort_alsa.h" +#include "MidiOutPort.h" +#include "MidiOutPort_linux.h" +#include "MidiOutPort_oss.h" +#include "MidiOutPort_unsupported.h" +#include "MidiOutPort_visual.h" +#include "MidiOutput.h" +#include "MidiPort.h" +#include "notenames.h" +#include "Options.h" +#include "Options_private.h" +#include "Sequencer_alsa.h" +#include "Sequencer_oss.h" +#include "sigConfiguration.h" +#include "SigTimer.h" +#include "Voice.h" + + +#endif /* _MIDIIO_H_INCLUDED */ + + + +// md5sum: b389c20c620865344d827a88a0fb048d - midiiolib.h =css= 20030102 diff --git a/src/midiio/include/notenames.h b/src/midiio/include/notenames.h new file mode 100644 index 0000000..ce9d505 --- /dev/null +++ b/src/midiio/include/notenames.h @@ -0,0 +1,219 @@ +// +// Programmer: Craig Stuart Sapp (from 18Dec1997) +// Creation Date: 26 December 1997 +// Last Modified: 26 December 1997 +// Filename: ...sig/code/control/misc/notenames.h +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/include/notenames.h +// Syntax: C +// +// Description: Defines for pitch names of midi key numbers +// + +#ifndef _NOTENAMES_H_INCLUDED +#define _NOTENAMES_H_INCLUDED + +#define C00 (0) +#define Cs00 (1) +#define Db00 (1) +#define D00 (2) +#define Ds00 (3) +#define Eb00 (3) +#define E00 (4) +#define F00 (5) +#define Fs00 (6) +#define Gb00 (6) +#define G00 (7) +#define Gs00 (8) +#define Ab00 (8) +#define A00 (9) +#define As00 (10) +#define Bb00 (10) +#define B00 (11) + +#define C0 (12) +#define Cs0 (13) +#define Db0 (13) +#define D0 (14) +#define Ds0 (15) +#define Eb0 (15) +#define E0 (16) +#define F0 (17) +#define Fs0 (18) +#define Gb0 (18) +#define G0 (19) +#define Gs0 (20) +#define Ab0 (20) +#define A0 (21) +#define As0 (22) +#define Bb0 (22) + +/* + * Note that the following symbol B0 is used in + * unix in the file /usr/include/termios.h also as + * a symbol, so It is disabled for now in this file. + * termios.h is need in Unix for the KeyboardInput.h file + */ + +// #define B0 (23) + +#define C1 (24) +#define Cs1 (25) +#define Db1 (25) +#define D1 (26) +#define Ds1 (27) +#define Eb1 (27) +#define E1 (28) +#define F1 (29) +#define Fs1 (30) +#define Gb1 (30) +#define G1 (31) +#define Gs1 (32) +#define Ab1 (32) +#define A1 (33) +#define As1 (34) +#define Bb1 (34) +#define B1 (35) + +#define C2 (36) +#define Cs2 (37) +#define Db2 (37) +#define D2 (38) +#define Ds2 (39) +#define Eb2 (39) +#define E2 (40) +#define F2 (41) +#define Fs2 (42) +#define Gb2 (42) +#define G2 (43) +#define Gs2 (44) +#define Ab2 (44) +#define A2 (45) +#define As2 (46) +#define Bb2 (46) +#define B2 (47) + +#define C3 (48) +#define Cs3 (49) +#define Db3 (49) +#define D3 (50) +#define Ds3 (51) +#define Eb3 (51) +#define E3 (52) +#define F3 (53) +#define Fs3 (54) +#define Gb3 (54) +#define G3 (55) +#define Gs3 (56) +#define Ab3 (56) +#define A3 (57) +#define As3 (58) +#define Bb3 (58) +#define B3 (59) + +#define C4 (60) +#define Cs4 (61) +#define Db4 (61) +#define D4 (62) +#define Ds4 (63) +#define Eb4 (63) +#define E4 (64) +#define F4 (65) +#define Fs4 (66) +#define Gb4 (66) +#define G4 (67) +#define Gs4 (68) +#define Ab4 (68) +#define A4 (69) +#define As4 (70) +#define Bb4 (70) +#define B4 (71) + +#define C5 (72) +#define Cs5 (73) +#define Db5 (73) +#define D5 (74) +#define Ds5 (75) +#define Eb5 (75) +#define E5 (76) +#define F5 (77) +#define Fs5 (78) +#define Gb5 (78) +#define G5 (79) +#define Gs5 (80) +#define Ab5 (81) +#define A5 (81) +#define As5 (82) +#define Bb5 (82) +#define B5 (83) + +#define C6 (84) +#define Cs6 (85) +#define Db6 (85) +#define D6 (86) +#define Ds6 (87) +#define Eb6 (87) +#define E6 (88) +#define F6 (89) +#define Fs6 (90) +#define Gb6 (90) +#define G6 (91) +#define Gs6 (92) +#define Ab6 (92) +#define A6 (93) +#define As6 (94) +#define Bb6 (94) +#define B6 (95) + +#define C7 (96) +#define Cs7 (97) +#define Db7 (97) +#define D7 (98) +#define Ds7 (99) +#define Eb7 (99) +#define E7 (100) +#define F7 (101) +#define Fs7 (102) +#define Gb7 (102) +#define G7 (103) +#define Gs7 (104) +#define Ab7 (104) +#define A7 (105) +#define As7 (106) +#define Bb7 (106) +#define B7 (107) + +#define C8 (108) +#define Cs8 (109) +#define Db8 (109) +#define D8 (110) +#define Ds8 (111) +#define Eb8 (111) +#define E8 (112) +#define F8 (113) +#define Fs8 (114) +#define Gb8 (114) +#define G8 (115) +#define Gs8 (116) +#define Ab8 (116) +#define A8 (117) +#define As8 (118) +#define Bb8 (118) +#define B8 (119) + +#define C9 (120) +#define Cs9 (121) +#define Db9 (121) +#define D9 (122) +#define Ds9 (123) +#define Eb9 (123) +#define E9 (124) +#define F9 (125) +#define Fs9 (126) +#define Gb9 (126) +#define G9 (127) + + +#endif /* _NOTENAMES_H_INCLUDED */ + + +// md5sum: c0f727163d32e04212a0ce5c8b6c4a6f - notenames.h =css= 20030102 diff --git a/src/midiio/include/sigConfiguration.h b/src/midiio/include/sigConfiguration.h new file mode 100644 index 0000000..b1e5f17 --- /dev/null +++ b/src/midiio/include/sigConfiguration.h @@ -0,0 +1,100 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Mon Dec 1 18:16:57 GMT-0800 1997 +// Last Modified: Mon Dec 1 18:16:57 GMT-0800 1997 +// Filename: ...sig/maint/code/misc/sigConfiguration.h +// Web Address: http://sig.sapp.org/include/sig/sigConfiguration.h +// Syntax: C +// +// Description: This file defines flags for different code setups: +// You specify the OS in a compiler flag and this file takes care +// of the rest of the defines for that OS. This file should +// automatically be included in any file which uses any of the +// define flags below. +// +// OS setup defines to use in compiling files: +// +// -DLINUX: Linux running on intel computers +// -DNEXTI: NeXT OS on Intel Hardware +// -DNEXTM: NeXT OS on Motorola Hardware +// -DSUN: Sun SPARCstations +// -DVISUAL: Windows 95/NT using Microsoft Visual C++ 5.0 +// -DHPUX: Hewlett-Packard Unix Workstations. +// -DIRIX: SGI computers with IRIX OS. +// +// +// Various options that can be defined for each OS. These +// defines may be mixed and matched in different OSes: +// +// -DOTHEREND: If the computer is little-endian, then this +// define switches the byte ordering behavior for writing/reading +// soundfiles. Intel computers need this define, most others +// will not.need this define. +// +// -DSHORTRAND: Indicates that the rand() function generates +// numbers between 0 and 0x7fff. The default without this +// option is a range between 0 and 0x7fffffff. +// +// -DINTEL: Indicates that the computer hardware uses an +// intel x86 CPU. Not used for anything right now except to +// define the endian flag (OTHEREND). +// +// -DMOTOROLA: Indicates that the computer hardware uses a +// Motorola 68k CPU. Not used for anything right now. +// +// + +#ifndef _SIGCONFIGURATION_H_INCLUDED +#define _SIGCONFIGURATION_H_INCLUDED + + +#ifdef LINUX + #define INTEL +#endif + + +#ifdef NEXTI + #define INTEL +#endif + + +#ifdef NEXT + #define MOTOROLA +#endif + + +#ifdef VISUAL + #define INTEL +#endif + + +#ifdef SUN + #define SHORTRAND +#endif + + +#ifdef HPUX + #define SHORTRAND +#endif + + +#ifdef IRIX + #define SHORTRAND +#endif + + +// These defines must come after the previous defines: + + +#ifdef INTEL + #define OTHEREND +#endif + + + +#endif /* _SIGCONFIGURATION_H_INCLUDED */ + + + +// md5sum: 32f74a7c264b158b83ff38db1ea885f8 - sigConfiguration.h =css= 20030102 diff --git a/src/midiio/src/FileIO.cpp b/src/midiio/src/FileIO.cpp new file mode 100644 index 0000000..93ef153 --- /dev/null +++ b/src/midiio/src/FileIO.cpp @@ -0,0 +1,761 @@ +// +// Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Fri May 9 22:30:32 PDT 1997 +// Last Modified: Sun Dec 14 03:29:39 GMT-0800 1997 +// Filename: ...sig/maint/code/sigBase/FileIO.cpp +// Web Address: http://sig.sapp.org/src/sigBase/FileIO.cpp +// Documentation: http://sig.sapp.org/doc/classes/FileIO +// Syntax: C++ +// +// Description: Derived from the fstream class, this class has +// functions which allow writing binary files in +// both little and big endian formats. Useful for +// writing files such as soundfiles and MIDI files +// which require numbers to be stored in a particular +// endian format. +// + +#include "FileIO.h" +#include "sigConfiguration.h" + +////////////////////////////// +// +// FileIO::FileIO -- +// + +FileIO::FileIO(void) { + // do nothing +}; + +FileIO::FileIO(const char* filename, std::ios::openmode state) : +#ifdef VISUAL /* for stupid LF-CR prevention in DOS */ + std::fstream(filename, state | ios::binary) { +#else + std::fstream(filename, state) { +#endif + // do nothing +}; + + + +////////////////////////////// +// +// FileIO::~FileIO -- +// + +FileIO::~FileIO() { + // do nothing +} + + + +////////////////////////////// +// +// FileIO::readBigEndian -- +// Read numbers from a file as big endian +// + +void FileIO::readBigEndian(char& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(uchar& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(short& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(ushort& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(long& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(ulong& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(int& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(uint& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(float& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + +void FileIO::readBigEndian(double& aNumber) { + #ifdef OTHEREND + readNotMachineEndian(aNumber); + #else + readMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::readLittleEndian -- +// Read numbers from a file as little endian +// + +void FileIO::readLittleEndian(char& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(uchar& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(short& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(ushort& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(long& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(ulong& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(int& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(uint& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(float& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + +void FileIO::readLittleEndian(double& aNumber) { + #ifdef OTHEREND + readMachineEndian(aNumber); + #else + readNotMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::readMachineEndian -- +// Read numbers from a file in the same endian as the computer. +// + +void FileIO::readMachineEndian(char& aNumber) { + this->read(&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(uchar& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(short& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(ushort& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(long& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(ulong& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(int& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(uint& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(float& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::readMachineEndian(double& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); +} + + + +////////////////////////////// +// +// FileIO::readNotMachineEndian -- +// Read numbers from a file with different endian from the computer. +// + +void FileIO::readNotMachineEndian(char& aNumber) { + this->read(&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(uchar& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(short& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(ushort& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(long& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(ulong& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(int& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(uint& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(float& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + +void FileIO::readNotMachineEndian(double& aNumber) { + this->read((char*)&aNumber, sizeof(aNumber)); + aNumber = flipBytes(aNumber); +} + + + +////////////////////////////// +// +// FileIO::writeBigEndian -- +// + +void FileIO::writeBigEndian(char aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(uchar aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(short aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(ushort aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(long aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(ulong aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(int aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(uint aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(float aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + +void FileIO::writeBigEndian(double aNumber) { + #ifdef OTHEREND + writeNotMachineEndian(aNumber); + #else + writeMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::writeLittleEndian -- +// + +void FileIO::writeLittleEndian(char aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(uchar aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(short aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(ushort aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(long aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(ulong aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(int aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(uint aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(float aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + +void FileIO::writeLittleEndian(double aNumber) { + #ifdef OTHEREND + writeMachineEndian(aNumber); + #else + writeNotMachineEndian(aNumber); + #endif +} + + + +////////////////////////////// +// +// FileIO::writeMachineEndian -- +// + +void FileIO::writeMachineEndian(char aNumber) { + this->write(&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(uchar aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(short aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(ushort aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(long aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(ulong aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(int aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(uint aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(float aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeMachineEndian(double aNumber) { + this->write((char*)&aNumber, sizeof(aNumber)); +} + + + +////////////////////////////// +// +// FileIO::writeNotMachineEndian -- +// + +void FileIO::writeNotMachineEndian(char aNumber) { + // aNumber = flipBytes(aNumber); + this->write(&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(uchar aNumber) { + // aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(short aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(ushort aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(long aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(ulong aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(int aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(uint aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(float aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + +void FileIO::writeNotMachineEndian(double aNumber) { + aNumber = flipBytes(aNumber); + this->write((char*)&aNumber, sizeof(aNumber)); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// flipBytes -- flip the bytes in a number +// + +char FileIO::flipBytes(char aNumber) { + return aNumber; +} + + +uchar FileIO::flipBytes(uchar aNumber) { + return aNumber; +} + + +short FileIO::flipBytes(short aNumber) { + static uchar output[2]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[1]; + output[1] = input[0]; + + return *((short*)(&output)); +} + + +ushort FileIO::flipBytes(ushort aNumber) { + static uchar output[2]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[1]; + output[1] = input[0]; + + return *((ushort*)(&output)); +} + + +long FileIO::flipBytes(long aNumber) { + static uchar output[4]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[3]; + output[1] = input[2]; + output[2] = input[1]; + output[3] = input[0]; + + return *((long*)(&output)); +} + + +ulong FileIO::flipBytes(ulong aNumber) { + static uchar output[4]; + static uchar* input; + input = (uchar*)(&aNumber); + + output[0] = input[3]; + output[1] = input[2]; + output[2] = input[1]; + output[3] = input[0]; + + return *((ulong*)(&output)); +} + + +int FileIO::flipBytes(int aNumber) { + static uchar output[sizeof(uint)]; + static uchar* input; + input = (uchar*)(&aNumber); + + for(uint i=0; i +type FileIO::flipBytes(type aThing) { + uchar* input = (uchar*)(&aNumber); + uchar output[sizeof(aThing)]; + + for(int i=0; i +// Creation Date: Fri Nov 26 14:12:01 PST 1999 +// Last Modified: Fri Dec 2 13:26:29 PST 1999 +// Last Modified: Wed Dec 13 10:33:30 PST 2000 (modified sorting routine) +// Last Modified: Tue Jan 22 23:23:37 PST 2002 (allowed reading of meta events) +// Filename: ...sig/src/sigInfo/MidiFile.cpp +// Web Address: http://sig.sapp.org/src/sigInfo/MidiFile.cpp +// Syntax: C++ +// +// Description: A class which can read/write Standard MIDI files. +// MIDI data is stored by track in an array. This +// class is used for example in the MidiPerform class. +// + +#include "MidiFile.h" +#include + +////////////////////////////// +// +// _MFEvent::_MFEvent -- +// + +_MFEvent::_MFEvent(void) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(0); +} + +_MFEvent::_MFEvent(int command) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(1); + data[0] = (uchar)command; +} + +_MFEvent::_MFEvent(int command, int param1) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(2); + data[0] = (uchar)command; + data[1] = (uchar)param1; +} + +_MFEvent::_MFEvent(int command, int param1, int param2) { + time = 0; + track = 0; + data.allowGrowth(); + data.setSize(3); + data[0] = (uchar)command; + data[1] = (uchar)param1; + data[2] = (uchar)param2; +} + +_MFEvent::_MFEvent(int aTrack, int command, int param1, int param2) { + time = 0; + track = aTrack; + data.allowGrowth(); + data.setSize(3); + data[0] = (uchar)command; + data[1] = (uchar)param1; + data[2] = (uchar)param2; +} + +_MFEvent::_MFEvent(int aTime, int aTrack, int command, int param1, int param2) { + time = aTime; + track = aTrack; + data.allowGrowth(); + data.setSize(3); + data[0] = (uchar)command; + data[1] = (uchar)param1; + data[2] = (uchar)param2; +} + + + +////////////////////////////// +// +// _MFEvent::~MFEvent +// + +_MFEvent::~_MFEvent() { + time = -1; + track = -1; + data.setSize(0); +} + + + +////////////////////////////// +// +// MidiFile::MidiFile -- +// + +MidiFile::MidiFile(void) { + ticksPerQuarterNote = 48; // time base of file + trackCount = 1; // # of tracks in file + theTrackState = TRACK_STATE_SPLIT; // joined or split + theTimeState = TIME_STATE_DELTA; // absolute or delta + events.setSize(1); + events[0] = new Collection<_MFEvent>; + events[0]->setSize(0); + events[0]->allowGrowth(1); + readFileName = new char[1]; + readFileName[0] = '\0'; +} + + +MidiFile::MidiFile(char* aFile) { + ticksPerQuarterNote = 48; // time base of file + trackCount = 1; // # of tracks in file + theTrackState = TRACK_STATE_SPLIT; // joined or split + theTimeState = TIME_STATE_DELTA; // absolute or delta + events.setSize(1); + events[0] = new Collection<_MFEvent>; + events[0]->setSize(0); + events[0]->allowGrowth(1); + readFileName = new char[1]; + readFileName[0] = '\0'; + read(aFile); +} + + + +////////////////////////////// +// +// MidiFile::~MidiFile -- +// + +MidiFile::~MidiFile() { + if (readFileName != NULL) { + delete [] readFileName; + readFileName = NULL; + } + + erase(); + + if (events[0] != NULL) { + delete events[0]; + events[0] = NULL; + } + +} + + + +////////////////////////////// +// +// MidiFile::absoluteTime -- convert the time data to +// absolute time, which means that the time field +// in the _MFEvent struct represents the exact tick +// time to play the event rather than the time since +// the last event to wait untill playing the current +// event. +// + +void MidiFile::absoluteTime(void) { + if (getTimeState() == TIME_STATE_ABSOLUTE) { + return; + } + int i, j; + int length = getNumTracks(); + int* timedata = new int[length]; + for (i=0; igetSize() > 0) { + timedata[i] = (*events[i])[0].time; + } else { + continue; + } + for (j=1; jgetSize(); j++) { + timedata[i] += (*events[i])[j].time; + (*events[i])[j].time = timedata[i]; + } + } + theTimeState = TIME_STATE_ABSOLUTE; + delete [] timedata; +} + +////////////////////////////// +// +// MidiFile::addEvent -- +// + +int MidiFile::addEvent(int aTrack, int aTime, Array& midiData) { + _MFEvent anEvent; + anEvent.time = aTime; + anEvent.track = aTrack; + anEvent.data = midiData; + + events[aTrack]->append(anEvent); + return events[aTrack]->getSize() - 1; +} + + + +////////////////////////////// +// +// MidiFile::addTrack -- adds a blank track at end of the +// track list. Returns the track number of the added +// track. +// + +int MidiFile::addTrack(void) { + int length = getNumTracks(); + events.setSize(length+1); + events[length] = new Collection<_MFEvent>; + events[length]->setSize(10000); + events[length]->setSize(0); + events[length]->allowGrowth(1); + return length; +} + +int MidiFile::addTrack(int count) { + int length = getNumTracks(); + events.setSize(length+count); + int i; + for (i=0; i; + events[length + i]->setSize(10000); + events[length + i]->setSize(0); + events[length + i]->allowGrowth(1); + } + return length + count - 1; +} + + +////////////////////////////// +// +// MidiFile::allocateEvents -- +// + +void MidiFile::allocateEvents(int track, int aSize) { + int oldsize = events[track]->getSize(); + if (oldsize < aSize) { + events[track]->setSize(aSize); + events[track]->setSize(oldsize); + } +} + + + +////////////////////////////// +// +// MidiFile::deleteTrack -- remove a track from the MidiFile. +// Tracks are numbered starting at track 0. +// + +void MidiFile::deleteTrack(int aTrack) { + int length = getNumTracks(); + if (aTrack < 0 || aTrack >= length) { + return; + } + if (length == 1) { + return; + } + delete events[aTrack]; + for (int i=aTrack; igetSize() > 0) { + timedata[i] = (*events[i])[0].time; + } else { + continue; + } + for (j=1; jgetSize(); j++) { + temp = (*events[i])[j].time; + (*events[i])[j].time = temp - timedata[i]; + timedata[i] = temp; + } + } + theTimeState = TIME_STATE_DELTA; + delete [] timedata; +} + + + +////////////////////////////// +// +// MidiFile::erase -- make the MIDI file empty with one +// track with no data in it. +// + +void MidiFile::erase(void) { + int length = getNumTracks(); + for (int i=0; i; + events[0]->setSize(0); + events[0]->allowGrowth(1); +} + + +void MidiFile::clear(void) { + MidiFile::erase(); +} + + + +////////////////////////////// +// +// MidiFile::getEvent -- return the event at the given index in the +// specified track. +// + +_MFEvent& MidiFile::getEvent(int aTrack, int anIndex) { + return (*events[aTrack])[anIndex]; +} + + + +////////////////////////////// +// +// MidiFile::getTicksPerQuarterNote -- returns the number of +// time units that are supposed to occur during a quarternote. +// + +int MidiFile::getTicksPerQuarterNote(void) { + return ticksPerQuarterNote; +} + + + +////////////////////////////// +// +// MidiFile::getTrackCount -- return the number of tracks in +// the Midi File. +// + +int MidiFile::getTrackCount(void) { + return events.getSize(); +} + +int MidiFile::getNumTracks(void) { + return events.getSize(); +} + + + +////////////////////////////// +// +// MidiFile::getNumEvents -- returns the number of events +// in a given track. +// + +int MidiFile::getNumEvents(int aTrack) { + return events[aTrack]->getSize(); +} + + + +////////////////////////////// +// +// MidiFile::joinTracks -- merge the data from all tracks, +// but keeping the identity of the tracks unique so that +// the function splitTracks can be called to split the +// tracks into separate units again. The style of the +// MidiFile when read from a file is with tracks split. +// + +void MidiFile::joinTracks(void) { + if (getTrackState() == TRACK_STATE_JOINED) { + return; + } + if (getNumTracks() == 1) { + return; + } + + Collection <_MFEvent>* joinedTrack; + joinedTrack = new Collection<_MFEvent>; + joinedTrack->setSize(200000); + joinedTrack->setSize(0); + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_DELTA) { + absoluteTime(); + } + int i, j; + int length = getNumTracks(); + for (i=0; igetSize(); j++) { + joinedTrack->append((*events[i])[j]); + } + } + + erase(); + + delete events[0]; + events[0] = joinedTrack; + sortTracks(); + if (oldTimeState == TIME_STATE_DELTA) { + deltaTime(); + } +} + + + +////////////////////////////// +// +// MidiFile::mergeTracks -- combine the data from two +// tracks into one. Placing the data in the first +// track location listed, and Moving the other tracks +// in the file around to fill in the spot where Track2 +// used to be. The results of this function call cannot +// be reversed. +// + +void MidiFile::mergeTracks(int aTrack1, int aTrack2) { + Collection <_MFEvent>* mergedTrack; + mergedTrack = new Collection<_MFEvent>; + mergedTrack->setSize(0); + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_DELTA) { + absoluteTime(); + } + int i, j; + int length = getNumTracks(); + for (i=0; igetSize(); i++) { + mergedTrack->append((*events[aTrack1])[i]); + } + for (j=0; jgetSize(); i++) { + (*events[aTrack2])[i].track = aTrack1; + mergedTrack->append((*events[aTrack2])[i]); + } + + sortTrack(*mergedTrack); + + delete events[aTrack1]; + + events[aTrack1] = mergedTrack; + + for (i=aTrack2; i; + events[z]->setAllocSize(10000); + events[z]->setSize(0); + events[z]->allowGrowth(1); + } + + // read ticks per quarter note + short signeddata; + inputfile.readBigEndian(signeddata); + if (signeddata <= 0) { + std::cout << "Error: cannot handle SMTP tick values for quarter notes" + " yet" << std::endl; + return 0; + } + ticksPerQuarterNote = signeddata; + + ////////////////////////////////////////////////// + // + // now read individual tracks: + // + + uchar runningCommand = 0; + _MFEvent event; + int absticks; + int barline; + + for (int i=0; isetSize(longdata/2); + events[i]->setSize(0); + + // process the track + absticks = 0; + barline = 1; + while (!inputfile.eof()) { + longdata = extractVlvTime(inputfile); +//std::cout << "ticks = " << longdata << std::endl; + absticks += longdata; + extractMidiData(inputfile, event.data, runningCommand); +//std::cout << "command = " << std::hex << (int)event.data[0] << std::dec << std::endl; + if (event.data[0] == 0xff && (event.data[1] == 1 || + event.data[1] == 2 || event.data[1] == 3 || event.data[1] == 4)) { + // mididata.append('\0'); + // std::cout << '\t'; + // for (int m=0; mappend(event); + } else { + event.time = absticks; + event.track = i; + events[i]->append(event); + } + + } + + } + // std::cout << std::endl; + + theTimeState = TIME_STATE_ABSOLUTE; + return 1; +} + + + +////////////////////////////// +// +// MidiFile::setTicksPerQuarterNote -- +// + +void MidiFile::setTicksPerQuarterNote(int ticks) { + ticksPerQuarterNote = ticks; +} + + + +////////////////////////////// +// +// MidiFile::sortTrack -- +// + +void MidiFile::sortTrack(Collection<_MFEvent>& trackData) { + qsort(trackData.getBase(), trackData.getSize(), + sizeof(_MFEvent), eventcompare); +} + + + +////////////////////////////// +// +// MidiFile::sortTracks -- sort all tracks in the MidiFile. +// + +void MidiFile::sortTracks(void) { + for (int i=0; igetSize(); + for (i=0; i maxTrack) { + maxTrack = (*events[0])[i].track; + } + } + + Collection<_MFEvent>* olddata = events[0]; + events[0] = NULL; + events.setSize(maxTrack); + for (i=0; i; + events[i]->setSize(0); + events[i]->allowGrowth(); + } + + int trackValue = 0; + for (i=0; length; i++) { + trackValue = (*olddata)[i].track; + events[trackValue]->append((*olddata)[i]); + } + + delete olddata; + + if (oldTimeState == TIME_STATE_DELTA) { + deltaTime(); + } +} + + + +////////////////////////////// +// +// MidiFile::timeState -- returns what type of time method is +// being used: either TIME_STATE_ABSOLUTE or TIME_STATE_DELTA. +// + +int MidiFile::getTimeState(void) { + return theTimeState; +} + + + +////////////////////////////// +// +// MidiFile::getTrackState -- returns what type of track method +// is being used: either TRACK_STATE_JOINED or TRACK_STATE_SPLIT. +// + +int MidiFile::getTrackState(void) { + return theTrackState; +} + + + +////////////////////////////// +// +// MidiFile::write -- write a standard MIDI file from data. +// + +int MidiFile::write(const char* aFile) { + int oldTimeState = getTimeState(); + if (oldTimeState == TIME_STATE_ABSOLUTE) { + deltaTime(); + } + + #ifdef VISUAL + FileIO outputfile(aFile, ios::out | ios::noreplace | ios::binary); + #else + // ios::noreplace does not exists anymore in GCC 3.x + FileIO outputfile(aFile, std::ios::out /* | std::ios::noreplace */); + #endif + + if (!outputfile.is_open()) { + std::cout << "Error: could not write: " << aFile << std::endl; + exit(1); + } + + // write the header of the Standard MIDI File + + char ch; + // 1. The characters "MThd" + ch = 'M'; + outputfile.writeBigEndian(ch); + ch = 'T'; + outputfile.writeBigEndian(ch); + ch = 'h'; + outputfile.writeBigEndian(ch); + ch = 'd'; + outputfile.writeBigEndian(ch); + + // 2. write the size of the header (alwas a "6" stored in unsigned long + ulong longdata = 6; + outputfile.writeBigEndian(longdata); + + // 3. MIDI file format, type 0, 1, or 2 + ushort shortdata; + if (getNumTracks() == 1) { + shortdata = 0; + } else { + shortdata = 1; + } + outputfile.writeBigEndian(shortdata); + + // 4. write out the number of tracks. + shortdata = getNumTracks(); + outputfile.writeBigEndian(shortdata); + + // 5. write out the number of ticks per quarternote. (avoiding SMTPE for now) + shortdata = getTicksPerQuarterNote(); + outputfile.writeBigEndian(shortdata); + + // now write each track. + Array trackdata; + uchar endoftrack[4] = {0, 0xff, 0x2f, 0x00}; + int i, j, k; + int size; + for (i=0; igetSize(); j++) { + writeVLValue((*events[i])[j].time, trackdata); + for (k=0; k<(*events[i])[j].data.getSize(); k++) { + trackdata.append((*events[i])[j].data[k]); + } + } + size = trackdata.getSize(); + if ((trackdata[size-3] != 0xff) && (trackdata[size-2] != 0x2f)) { + trackdata.append(endoftrack[0]); + trackdata.append(endoftrack[1]); + trackdata.append(endoftrack[2]); + trackdata.append(endoftrack[3]); + } + + // now ready to write to MIDI file. + + // first write the track ID marker "MTrk": + ch = 'M'; + outputfile.writeBigEndian(ch); + ch = 'T'; + outputfile.writeBigEndian(ch); + ch = 'r'; + outputfile.writeBigEndian(ch); + ch = 'k'; + outputfile.writeBigEndian(ch); + + // A. write the size of the MIDI data to follow: + longdata = trackdata.getSize(); + outputfile.writeBigEndian(longdata); + + // B. write the actual data + outputfile.write((char*)trackdata.getBase(), trackdata.getSize()); + } + + if (oldTimeState == TIME_STATE_ABSOLUTE) { + absoluteTime(); + } + + outputfile.close(); + + return 1; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// MidiF::extractMidiData -- +// + +void MidiFile::extractMidiData(FileIO& inputfile, Array& array, + uchar& runningCommand) { + + uchar byte; + array.setSize(0); + array.allowGrowth(); + int runningQ; + + inputfile.readBigEndian(byte); + + if (byte < 0x80) { + runningQ = 1; + if (runningCommand == 0) { + std::cout << "Error: running command with no previous command" << std::endl; + exit(1); + } + } else { + runningCommand = byte; + runningQ = 0; + } + + array.append(runningCommand); + if (runningQ) { + array.append(byte); + } + + uchar metai; + switch (runningCommand & 0xf0) { + case 0x80: // note off (2 more bytes) + case 0x90: // note on (2 more bytes) + case 0xA0: // aftertouch (2 more bytes) + case 0xB0: // cont. controller (2 more bytes) + case 0xE0: // pitch wheel (2 more bytes) + inputfile.readBigEndian(byte); + array.append(byte); + if (!runningQ) { + inputfile.readBigEndian(byte); + array.append(byte); + } + break; + case 0xC0: // patch change (1 more byte) + case 0xD0: // channel pressure (1 more byte) + if (!runningQ) { + inputfile.readBigEndian(byte); + array.append(byte); + } + break; + case 0xF0: + switch (runningCommand) { + case 0xff: // meta event + { + if (!runningQ) { + inputfile.readBigEndian(byte); // meta type + array.append(byte); + } + inputfile.readBigEndian(metai); // meta size + array.append(metai); + for (uchar j=0; j 0x7f) { + std::cout << "Error: VLV value was too long" << std::endl; + exit(1); + } + + uchar bytes[5] = {a, b, c, d, e}; + int count = 0; + while (bytes[count] > 0x7f && count < 5) { + count++; + } + count++; + + ulong output = 0; + for (int i=0; i& outdata) { + uchar bytes[5] = {0}; + bytes[0] = (uchar)(((ulong)aValue >> 28) & 0x7f); // most significant 5 bits + bytes[1] = (uchar)(((ulong)aValue >> 21) & 0x7f); // next largest 7 bits + bytes[2] = (uchar)(((ulong)aValue >> 14) & 0x7f); + bytes[3] = (uchar)(((ulong)aValue >> 7) & 0x7f); + bytes[4] = (uchar)(((ulong)aValue) & 0x7f); // least significant 7 bits + + int start = 0; + while (start<5 && bytes[start] == 0) start++; + + for (int i=start; i<4; i++) { + bytes[i] = bytes[i] | 0x80; + outdata.append(bytes[i]); + } + outdata.append(bytes[4]); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// external functions +// + + +////////////////////////////// +// +// eventcompare -- for sorting the tracks +// + +int eventcompare(const void* a, const void* b) { + _MFEvent& aevent = *((_MFEvent*)a); + _MFEvent& bevent = *((_MFEvent*)b); + + if (aevent.time > bevent.time) { + return 1; + } else if (aevent.time < bevent.time) { + return -1; + } else if (aevent.data[0] == 0xff && bevent.data[0] != 0xff) { + return 1; + } else if (bevent.data[0] == 0xff && aevent.data[0] != 0xff) { + return -1; + } else if (bevent.data[0] == 0xff && bevent.data[1] == 0x2f) { + return -1; + } else if (aevent.data[0] == 0xff && aevent.data[1] == 0x2f) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// operator<< -- for printing an ASCII version of the MIDI file +// + +std::ostream& operator<<(std::ostream& out, MidiFile& aMidiFile) { + int i, j, k; + out << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"; + out << "Number of Tracks: " << aMidiFile.getTrackCount() << "\n"; + out << "Time method: " << aMidiFile.getTimeState(); + if (aMidiFile.getTimeState() == TIME_STATE_DELTA) { + out << " (Delta timing)"; + } else if (aMidiFile.getTimeState() == TIME_STATE_ABSOLUTE) { + out << " (Absolute timing)"; + } else { + out << " (unknown method)"; + } + out << "\n"; + + out << "Divisions per Quarter Note: " << std::dec << aMidiFile.getTicksPerQuarterNote() << "\n"; + for (i=0; i +// Creation Date: Sun Mar 15 10:55:56 GMT-0800 1998 +// Last Modified: Sun Mar 15 10:55:56 GMT-0800 1998 +// Filename: ...sig/code/control/MidiFileWrite/MidiFileWrite.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiFileWrite.cpp +// Syntax: C++ +// +// Description: The MidiFileWrite class will write out a Type 0 MidiFile. +// Used for recording MIDI data streams into Standard +// MIDI files. +// + +#include "MidiFileWrite.h" +#include "SigTimer.h" +#include + + +////////////////////////////// +// +// MidiFileWrite::MidiFileWrite +// default value: startTime = -1 +// + +MidiFileWrite::MidiFileWrite(void) { + trackSize = 0; + lastPlayTime = 0; + midifile = NULL; + openQ = 0; +} + + +MidiFileWrite::MidiFileWrite(const char* aFilename, int startTime) { + trackSize = 0; + lastPlayTime = 0; + midifile = NULL; + openQ = 0; + setup(aFilename, startTime); +} + + + +////////////////////////////// +// +// MidiFileWrite::~MidiFileWrite +// + +MidiFileWrite::~MidiFileWrite() { + close(); +} + + + +////////////////////////////// +// +// MidiFileWrite::close +// + +void MidiFileWrite::close(void) { + writeRaw(0, 0xff, 0x2f, 0); // end of track meta event + + midifile->seekg(18); + midifile->writeBigEndian(trackSize); + + midifile->close(); + + midifile = NULL; + openQ = 0; +} + + + +////////////////////////////// +// +// MidiFileWrite::setup -- writes the Midi file header and +// prepares the midifile for writing of data +// default value: startTime = -1 +// + +void MidiFileWrite::setup(const char* aFilename, int startTime) { + if (openQ) { + close(); + } + + if (midifile != NULL) delete midifile; + midifile = new FileIO; + midifile->open(aFilename, std::ios::out); + + // write the header chunk + *midifile << "MThd"; // file identification: MIDI file + midifile->writeBigEndian(6L); // size of header (always 6) + midifile->writeBigEndian((short)0); // format: type 0; + midifile->writeBigEndian((short)0); // num of tracks (always 0 for type 0) + midifile->writeBigEndian((short)1000); // divisions per quarter note + + + // write the track header + *midifile << "MTrk"; + midifile->writeBigEndian(0xffffL); // the track size which will + // be corrected with close() + + + // the midifile stream is now setup for writing + // track events + + openQ = 1; + + start(); // start can be called later and will behave well + // as long as no track events have been written +} + + + +////////////////////////////// +// +// MidiFileWrite::start +// default value: startTime = -1; +// + +void MidiFileWrite::start(int startTime) { + if (startTime < 0) { + SigTimer localTime; + lastPlayTime = localTime.getTime(); + } else { + lastPlayTime = startTime; + } +} + + + +////////////////////////////// +// +// MidiFileWrite::writeAbsolute -- considers the time data +// to be the current time. It will generate a difference +// time with the previously stored last playing time. +// + +void MidiFileWrite::writeAbsolute(int aTime, int command, int p1, int p2) { + writeVLValue(aTime - lastPlayTime); + writeRaw((uchar)command, (uchar)p1, (uchar)p2); + lastPlayTime = aTime; +} + +void MidiFileWrite::writeAbsolute(int aTime, int command, int p1) { + writeVLValue(aTime - lastPlayTime); + writeRaw((uchar)command, (uchar)p1); + lastPlayTime = aTime; +} + +void MidiFileWrite::writeAbsolute(int aTime, int command) { + writeVLValue(aTime - lastPlayTime); + writeRaw((uchar)command); + lastPlayTime = aTime; +} + + + +////////////////////////////// +// +// MidiFileWrite::writeRaw -- write an event byte to the midifile +// + +void MidiFileWrite::writeRaw(uchar aByte) { + assert(midifile != NULL); + *midifile << aByte; + trackSize++; +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte) { + writeRaw(aByte); + writeRaw(bByte); +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte, uchar cByte) { + writeRaw(aByte); + writeRaw(bByte); + writeRaw(cByte); +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte, uchar cByte, + uchar dByte) { + writeRaw(aByte); + writeRaw(bByte); + writeRaw(cByte); + writeRaw(dByte); +} + + +void MidiFileWrite::writeRaw(uchar aByte, uchar bByte, uchar cByte, + uchar dByte, uchar eByte) { + writeRaw(aByte); + writeRaw(bByte); + writeRaw(cByte); + writeRaw(dByte); + writeRaw(eByte); +} + + +void MidiFileWrite::writeRaw(uchar* anArray, int arraySize) { + for (int i=0; i> 28) & 0x7f); // most significant 5 bits + bytes[1] = (uchar)((aValue >> 21) & 0x7f); // next largest 7 bits + bytes[2] = (uchar)((aValue >> 14) & 0x7f); + bytes[3] = (uchar)((aValue >> 7) & 0x7f); + bytes[4] = (uchar)((aValue) & 0x7f); // least significant 7 bits + + int start = 0; + while (start<5 && bytes[start] == 0) start++; + + for (int i=start; i<4; i++) { + writeRaw((uchar)(bytes[i] | 0x80)); + } + writeRaw(bytes[4]); +} + +// md5sum: 251468fa23862745f0cf36f359bccc17 - MidiFileWrite.cpp =css= 20030102 diff --git a/src/midiio/src/MidiIO.cpp b/src/midiio/src/MidiIO.cpp new file mode 100644 index 0000000..26363f2 --- /dev/null +++ b/src/midiio/src/MidiIO.cpp @@ -0,0 +1,283 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 21 December 1997 +// Last Modified: Sun Jan 25 15:45:18 GMT-0800 1998 +// Filename: ...sig/code/control/MidiIO/MidiIO.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiIO.cpp +// Syntax: C++ +// +// Description: A unified class for MidiInput and MidiOutput that handles +// MIDI input and output connections. The Synthesizer +// and RadioBaton classes are derived from this class. +// + +#include "MidiIO.h" + + +////////////////////////////// +// +// MidiIO::MidiIO +// + +MidiIO::MidiIO(void) : MidiOutput(), MidiInput() { + // does nothing +} + + +MidiIO::MidiIO(int outPort, int inPort) : + MidiOutput(outPort), MidiInput(inPort) { + // does nothing +} + + + +////////////////////////////// +// +// MidiIO::~MidiIO +// + +MidiIO::~MidiIO() { + // does nothing +} + + + +////////////////////////////// +// +// MidiIO::close +// + +void MidiIO::close(void) { + MidiInput::close(); + MidiOutput::close(); +} + + + +////////////////////////////// +// +// MidiIO::closeInput +// + +void MidiIO::closeInput(void) { + MidiInput::close(); +} + + + +////////////////////////////// +// +// MidiIO::closeOutput +// + +void MidiIO::closeOutput(void) { + MidiOutput::close(); +} + + + +////////////////////////////// +// +// MidiIO::getChannelInOffset -- return the MIDI channel offset of +// the MIDI input. +// + +int MidiIO::getChannelInOffset(void) const { + return MidiInPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiIO::getChannelOutOffset -- return the MIDI channel offset of +// the MIDI output. +// + +int MidiIO::getChannelOutOffset (void) const { + return MidiOutPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiIO::getInputPort +// + +int MidiIO::getInputPort(void) { + return MidiInput::getPort(); +} + + + +////////////////////////////// +// +// MidiIO::getInputTrace +// + +int MidiIO::getInputTrace(void) { + return MidiInput::getTrace(); +} + + + +////////////////////////////// +// +// MidiIO::getNumInputPorts +// + +int MidiIO::getNumInputPorts(void) { + return MidiInput::getNumPorts(); +} + + + +////////////////////////////// +// +// MidiIO::getNumOutputPorts +// + +int MidiIO::getNumOutputPorts(void) { + return MidiOutput::getNumPorts(); +} + + + +////////////////////////////// +// +// MidiIO::getOutputPort +// + +int MidiIO::getOutputPort(void) { + return MidiOutput::getPort(); +} + + + +////////////////////////////// +// +// MidiIO::getOutputTrace +// + +int MidiIO::getOutputTrace(void) { + return MidiOutput::getTrace(); +} + + + +////////////////////////////// +// +// MidiIO::open +// + +int MidiIO::open(void) { + if (MidiInput::open()) { + return MidiOutput::open(); + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiIO::openInput +// + +int MidiIO::openInput(void) { + return MidiInput::open(); +} + + + +////////////////////////////// +// +// MidiIO::openOutput +// + +int MidiIO::openOutput(void) { + return MidiOutput::open(); +} + + + +////////////////////////////// +// +// MidiIO::setChannelOffset -- sets the MIDI channel offset +// + +void MidiIO::setChannelOffset(int anOffset) { + MidiInPort::setChannelOffset(anOffset); + MidiOutPort::setChannelOffset(anOffset); +} + + + +////////////////////////////// +// +// MidiIO::setInputPort +// + +void MidiIO::setInputPort(int aPort) { + MidiInput::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiIO::setInputTrace +// + +void MidiIO::setInputTrace(int aState) { + MidiInput::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiIO::setOutputPort +// + +void MidiIO::setOutputPort(int aPort) { + MidiOutput::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiIO::setOutputTrace +// + +void MidiIO::setOutputTrace(int aState) { + MidiOutput::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiIO::toggleInputTrace +// + +void MidiIO::toggleInputTrace(void) { + MidiInput::toggleTrace(); +} + + +////////////////////////////// +// +// MidiIO::toggleOutputTrace +// + +void MidiIO::toggleOutputTrace(void) { + MidiOutput::toggleTrace(); +} + + + +// md5sum: 860227c67236eb6f8897ae67f1338cb0 - MidiIO.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_alsa.cpp b/src/midiio/src/MidiInPort_alsa.cpp new file mode 100644 index 0000000..55d22b0 --- /dev/null +++ b/src/midiio/src/MidiInPort_alsa.cpp @@ -0,0 +1,1038 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun May 14 22:03:16 PDT 2000 +// Last Modified: Sat Oct 13 16:11:10 PDT 2001 (updated for ALSA 0.9) +// Last Modified: Fri Oct 26 14:41:36 PDT 2001 (running status for 0xa0 and 0xd0 +// fixed by Daniel Gardner) +// Last Modified: Mon Nov 19 17:52:15 PST 2001 (thread on exit improved) +// Filename: ...sig/code/control/MidiInPort/linux/MidiInPort_alsa.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInPort_alsa.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#if defined(LINUX) && defined(ALSA) + +#include "MidiInPort_alsa.h" +#include +#include +#include +#include +#include + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables + +int MidiInPort_alsa::numDevices = 0; +int MidiInPort_alsa::objectCount = 0; +int* MidiInPort_alsa::portObjectCount = NULL; +CircularBuffer** MidiInPort_alsa::midiBuffer = NULL; +int MidiInPort_alsa::channelOffset = 0; +SigTimer MidiInPort_alsa::midiTimer; +int* MidiInPort_alsa::pauseQ = NULL; +int* MidiInPort_alsa::trace = NULL; +std::ostream* MidiInPort_alsa::tracedisplay = &std::cout; +Array MidiInPort_alsa::midiInThread; +int* MidiInPort_alsa::sysexWriteBuffer = NULL; +Array** MidiInPort_alsa::sysexBuffers = NULL; + +Array MidiInPort_alsa::threadinitport; + + + +////////////////////////////// +// +// MidiInPort_alsa::MidiInPort_alsa +// default values: autoOpen = 1 +// + +MidiInPort_alsa::MidiInPort_alsa(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_alsa::MidiInPort_alsa(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::~MidiInPort_alsa +// + +MidiInPort_alsa::~MidiInPort_alsa() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiInPort_alsa object count!: " + << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_alsa::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_alsa::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::close +// + +void MidiInPort_alsa::close(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; + Sequencer_alsa::closeInput(getPort()); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::closeAll -- +// + +void MidiInPort_alsa::closeAll(void) { + for (int i=0; iextract(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getBufferSize -- returns the maximum possible number +// of MIDI messages that can be stored in the buffer +// + +int MidiInPort_alsa::getBufferSize(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getSize(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_alsa::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_alsa::getCount(void) { + if (getPort() == -1) return 0; + return midiBuffer[getPort()]->getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getName -- returns the name of the port. +// returns "" if no name. Name is valid until all instances +// of MIDI classes are. +// + +const char* MidiInPort_alsa::getName(void) { + if (getPort() == -1) { + return "Null ALSA MIDI Input"; + } + return getInputName(getPort()); +} + + +const char* MidiInPort_alsa::getName(int i) { + return getInputName(i); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_alsa::getNumPorts(void) { + return getNumInputs(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_alsa::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_alsa::getPortStatus(void) { + return is_open_in(getPort()); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_alsa::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_alsa::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_alsa::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::insert +// + +void MidiInPort_alsa::insert(const MidiMessage& aMessage) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa::installSysex(uchar* anArray, int aSize) { + if (getPort() == -1) { + return -1; + } else { + return installSysexPrivate(getPort(), anArray, aSize); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa::installSysexPrivate(int port, uchar* anArray, int aSize) { + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i& temp = *midiBuffer[getPort()]; + return temp[index]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_alsa::open(void) { + if (getPort() == -1) return 0; + + int status = Sequencer_alsa::openInput(getPort()); + if (status) { + pauseQ[getPort()] = 0; + return 1; + } else { + pauseQ[getPort()] = 1; + return 0; + } + + return 0; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keeps the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_alsa::pause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_alsa::setBufferSize(int aSize) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setChannelOffset -- sets the MIDI chan offset, +// either 0 or 1. +// + +void MidiInPort_alsa::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setPort -- +// + +void MidiInPort_alsa::setPort(int aPort) { +// if (aPort == -1) return; + if (aPort < -1 || aPort >= getNumPorts()) { +// std::cerr << "Error: maximum port number is: " << getNumPorts()-1 +// << ", but you tried to access port: " << aPort << std::endl; +// exit(1); + } + else { + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_alsa::setTrace(int aState) { + if (getPort() == -1) return -1; + + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_alsa::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_alsa::unpause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_alsa::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_alsa::deinitialize(void) { + closeAll(); + + for (int i=0; i*[numDevices]; + + // allocate space for Midi input sysex buffer write indices + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + } + sysexWriteBuffer = new int[numDevices]; + + // allocate space for Midi input sysex buffers + if (sysexBuffers != NULL) { + std::cout << "Error: memory leak on sysex buffers initialization" << std::endl; + exit(1); + } + sysexBuffers = new Array*[numDevices]; + + int flag; + midiInThread.setSize(getNumPorts()); + threadinitport.setSize(getNumPorts()); + // initialize the static arrays + for (int i=0; i; + midiBuffer[i]->setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + threadinitport[i] = i; + flag = pthread_create(&midiInThread[i], NULL, + interpretMidiInputStreamPrivateALSA, &threadinitport[i]); + if (flag == -1) { + std::cout << "Unable to create MIDI input thread." << std::endl; + exit(1); + } + } + + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// friendly functions +// + + +////////////////////////////// +// +// interpretMidiInputStreamPrivateALSA -- handles the MIDI input stream +// for the various input devices from the ALSA MIDI driver. +// +// Note about system exclusive messages: +// System Exclusive messages are stored in a separate buffer from +// Other Midi messages since they can be variable in length. If +// The Midi Input returns a message with command byte 0xf0, then +// the p1() byte indicates the system exclusive buffer number that is +// holding the system exclusive data for that Midi message. There +// are 128 system exclusive buffers that are numbered between +// 0 and 127. These buffers are filled in a cycle. +// To extract a System exclusive message from MidiInPort_alsa, +// you first will receive a Message with a command byte of 0xf0. +// you can then access the data for that sysex by the command: +// MidiInPort_alsa::getSysex(buffer_number), this will return +// a pointer to the beginning of the sysex data. The first byte +// of the sysex data should be 0xf0, and the last byte of the data +// is 0xf7. All other bytes of data should be in the range from +// 0 to 127. You can also get the size of the sysex buffer by the +// following command: MidiInPort_alsa::getSysexSize(buffer_number). +// This command will tell you the number of bytes in the system +// exclusive message including the starting 0xf0 and the ending 0xf7. +// +// If you want to minimize memory useage of the system exclusive +// buffers you can run the command: +// MidiInPort_alsa::clearSysex(buffer_number); Otherwise the sysex +// buffer will be erased automatically the next time that the +// buffer number is cycled through when receiving more system exclusives. +// Allocated the allocated size of the system exclusive storage will +// not be adjusted when the computer replaces the system exclusive +// message unless more storage size is needed, clearSysex however, +// will resize the sysex buffer to its default size (currently 32 bytes). +// clearSysex() without arguments will resize all buffers so that +// they are allocated to the default size and will erase data from +// all buffers. You can spoof a system exclusive message coming in +// by installing a system exclusive message and then inserting +// the system message command into the input buffer of the MidiInPort +// class, int sysex_buffer = MidiInPort_alsa::installSysex( +// uchar *data, int size); will put the data into a sysex buffer and +// return the buffer number that it was placed into. +// +// This function assumes that System Exclusive messages cannot be sent +// as a running status messages. +// +// Note about MidiMessage time stamps: +// The MidiMessage::time field is a recording of the time that the +// first byte of the MidiMessage arrived. If the message is from +// running status mode, then the time that the first parameter byte +// arrived is stored. System exclusive message arrival times are +// recoreded at the time of the last byte (0xf7) arriving. This is +// because other system messages can be coming in while the sysex +// message is coming in. Anyway, sysex messages are not really to +// be used for real time MIDI messaging, so the exact moment that the +// first byte of the sysex came in is not important to me. +// +// + +void *interpretMidiInputStreamPrivateALSA(void * arg) { + int portToWatch = *(int*)arg; + if (portToWatch < 0 || portToWatch > 1000) { + // the port to watch is invalid -- because the program has died + // before the thread function could start. Cause of invalid port + // data should be examined more carefully. + return NULL; + } + + int* argsExpected = NULL; // MIDI parameter bytes expected to follow + int* argsLeft = NULL; // MIDI parameter bytes left to wait for + uchar packet[1]; // bytes for sequencer driver + MidiMessage* message = NULL; // holder for current MIDI message + int newSigTime = 0; // for millisecond timer + int lastSigTime = -1; // for millisecond timer + int zeroSigTime = -1; // for timing incoming events + int device = -1; // for sorting out the bytes by input device + Array* sysexIn; // MIDI Input sysex temporary storage + + // Note on the use of argsExpected and argsLeft for sysexs: + // If argsExpected is -1, then a sysex message is coming in. + // If argsLeft < 0, then the sysex message has not finished comming + // in. If argsLeft == 0 and argsExpected == -1, then the sysex + // has finished coming in and is to be sent to the correct + // location. + + // allocate space for MIDI messages, each device has a different message + // holding spot in case the messages overlap in the input stream + message = new MidiMessage[MidiInPort_alsa::numDevices]; + argsExpected = new int[MidiInPort_alsa::numDevices]; + argsLeft = new int[MidiInPort_alsa::numDevices]; + + sysexIn = new Array[MidiInPort_alsa::numDevices]; + for (int j=0; j 0 && + Sequencer_alsa::rawmidi_in[portToWatch] != NULL) { + packetReadCount = snd_rawmidi_read( + Sequencer_alsa::rawmidi_in[portToWatch], packet, 1); + } else { + usleep(100000); // sleep for 1/10th of a second if the Input + // port is not open. + continue; + } + + + if (packetReadCount != 1) { + // this if statement is used to prevent cases where the + // read function above will time out and return 0 bytes + // read. This if statment will also take care of -1 + // error return values by ignoring them. + continue; + } + + if (Sequencer_alsa::initialized == 0) { + continue; + } + + // determination of a full MIDI message from the input MIDI + // stream is based here on the observation that MIDI status + // bytes and subsequent data bytes are NOT returned in the same + // read() call. Rather, they are spread out over multiple read() + // returns, with only a single value per return. So if we + // find a status byte, we then determine the number of expected + // operands and process that number of subsequent read()s to + // to determine the complete midi message. + + // store the MIDI input device to which the incoming MIDI + // byte belongs. + device = portToWatch; + + // ignore the active sensing 0xfe and MIDI clock 0xf8 commands: + if (packet[0] == 0xfe || packet[0] == 0xf8) { + continue; + } + + if (packet[0] & 0x80) { // a command byte has arrived + switch (packet[0] & 0xf0) { + case 0xf0: + if (packet[0] == 0xf0) { + argsExpected[device] = -1; + argsLeft[device] = -1; + if (sysexIn[device].getSize() != 0) { + // ignore the command for now. It is most + // likely an active sensing message. + goto top_of_loop; + } else { + uchar datum = 0xf0; + sysexIn[device].append(datum); + } + } if (packet[0] == 0xf7) { + argsLeft[device] = 0; // indicates sysex is done + uchar datum = 0xf7; + sysexIn[device].append(datum); + } else if (argsExpected[device] != -1) { + // this is a system message that may or may + // not be coming while a sysex is coming in + argsExpected[device] = 0; + } else { + // this is a system message that is not coming + // while a system exclusive is coming in + //argsExpected[device] = 0; + } + break; + case 0xc0: + if (argsExpected[device] < 0) { + std::cout << "Error: received program change during sysex" + << std::endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + case 0xd0: + if (argsExpected[device] < 0) { + std::cout << "Error: received aftertouch message during" + " sysex" << std::endl; + exit(1); + } else { + argsExpected[device] = 1; + } + break; + default: + if (argsExpected[device] < 0) { + std::cout << "Error: received another message during sysex" + << std::endl; + exit(1); + } else { + argsExpected[device] = 2; + } + break; + } + if (argsExpected[device] >= 0) { + argsLeft[device] = argsExpected[device]; + } + + newSigTime = MidiInPort_alsa::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + + if (packet[0] != 0xf7) { + message[device].p0() = packet[0]; + } + message[device].p1() = 0; + message[device].p2() = 0; + message[device].p3() = 0; + + if (packet[0] == 0xf7) { + goto sysex_done; + } + } else if (argsLeft[device]) { // not a command byte coming in + if (message[device].time == 0) { + // store the receipt time of the first message byte + newSigTime = MidiInPort_alsa::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + } + + if (argsExpected[device] < 0) { + // continue processing a sysex message + sysexIn[device].append(packet[0]); + } else { + // handle a message other than a sysex message + if (argsLeft[device] == argsExpected[device]) { + message[device].p1() = packet[0]; + } else { + message[device].p2() = packet[0]; + } + argsLeft[device]--; + } + + // if MIDI message is complete, setup for running status, and + // insert note into proper buffer. + + if (argsExpected[device] >= 0 && !argsLeft[device]) { + + // store parameter data for running status + switch (message[device].p0() & 0xf0) { + case 0xc0: argsLeft[device] = 1; break; + case 0xd0: argsLeft[device] = 1; break; // fix by dan + default: argsLeft[device] = 2; break; + // 0x80 expects two arguments + // 0x90 expects two arguments + // 0xa0 expects two arguments + // 0xb0 expects two arguments + // 0xe0 expects two arguments + } + + lastSigTime = newSigTime; + + sysex_done: // come here when a sysex is completely done + + // insert the MIDI message into the appropriate buffer + // do not insert into buffer if the MIDI input device + // is paused (which can mean closed). Or if the + // pauseQ array is pointing to NULL (which probably means that + // things are about to shut down). + if (MidiInPort_alsa::pauseQ != NULL && + MidiInPort_alsa::pauseQ[device] == 0) { + if (argsExpected[device] < 0) { + // store the sysex in the MidiInPort_alsa + // buffer for sysexs and return the storage + // location: + int sysexlocation = + MidiInPort_alsa::installSysexPrivate(device, + sysexIn[device].getBase(), + sysexIn[device].getSize()); + + message[device].p0() = 0xf0; + message[device].p1() = sysexlocation; + + sysexIn[device].setSize(0); // empty the sysex storage + argsExpected[device] = 0; // no run status for sysex + argsLeft[device] = 0; // turn off sysex input flag + } + MidiInPort_alsa::midiBuffer[device]->insert( + message[device]); +// if (MidiInPort_alsa::callbackFunction != NULL) { +// MidiInPort_alsa::callbackFunction(device); +// } + if (MidiInPort_alsa::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << ':' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + message[device].time = 0; + } else { + if (MidiInPort_alsa::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << 'P' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + } + } + } + + } // end while (1) + + // This code is not yet reached, but should be made to do so eventually + + if (message != NULL) { + delete message; + message = NULL; + } + + if (argsExpected != NULL) { + delete argsExpected; + argsExpected = NULL; + } + + if (argsLeft != NULL) { + delete argsLeft; + argsLeft = NULL; + } + + if (sysexIn != NULL) { + delete sysexIn; + sysexIn = NULL; + } + + + return NULL; +} + + + +#endif // LINUX && ALSA + + + +// md5sum: 14663a91d1f5283e05ca36399d5ab767 - MidiInPort_alsa.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_alsa05.cpp b/src/midiio/src/MidiInPort_alsa05.cpp new file mode 100644 index 0000000..1aad849 --- /dev/null +++ b/src/midiio/src/MidiInPort_alsa05.cpp @@ -0,0 +1,995 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun May 14 22:03:16 PDT 2000 +// Last Modified: Wed Oct 3 22:28:20 PDT 2001 (frozen for ALSA 0.5) +// Last Modified: Fri Oct 26 14:41:36 PDT 2001 (running status for 0xa0 and 0xd0 +// fixed by Daniel Gardner) +// Filename: ...sig/code/control/MidiInPort/linux/MidiInPort_alsa05.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInPort_alsa05.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux ALSA sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#if defined(LINUX) && defined(ALSA05) + +#include "MidiInPort_alsa05.h" +#include +#include +#include +#include + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables + +int MidiInPort_alsa05::numDevices = 0; +int MidiInPort_alsa05::objectCount = 0; +int* MidiInPort_alsa05::portObjectCount = NULL; +CircularBuffer** MidiInPort_alsa05::midiBuffer = NULL; +int MidiInPort_alsa05::channelOffset = 0; +SigTimer MidiInPort_alsa05::midiTimer; +int* MidiInPort_alsa05::pauseQ = NULL; +int* MidiInPort_alsa05::trace = NULL; +ostream* MidiInPort_alsa05::tracedisplay = &cout; +Array MidiInPort_alsa05::midiInThread; +int* MidiInPort_alsa05::sysexWriteBuffer = NULL; +Array** MidiInPort_alsa05::sysexBuffers = NULL; + +Array MidiInPort_alsa05::threadinitport; + + + +////////////////////////////// +// +// MidiInPort_alsa05::MidiInPort_alsa05 +// default values: autoOpen = 1 +// + +MidiInPort_alsa05::MidiInPort_alsa05(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_alsa05::MidiInPort_alsa05(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::~MidiInPort_alsa05 +// + +MidiInPort_alsa05::~MidiInPort_alsa05() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + cerr << "Error: bad MidiInPort_alsa05 object count!: " + << objectCount << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_alsa05::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_alsa05::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::close +// + +void MidiInPort_alsa05::close(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::closeAll -- +// + +void MidiInPort_alsa05::closeAll(void) { + Sequencer_alsa05::close(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_alsa05::extract(void) { + if (getPort() == -1) { + MidiMessage temp; + return temp; + } + + return midiBuffer[getPort()]->extract(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getBufferSize -- returns the maximum possible number +// of MIDI messages that can be stored in the buffer +// + +int MidiInPort_alsa05::getBufferSize(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getSize(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_alsa05::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_alsa05::getCount(void) { + if (getPort() == -1) return 0; + return midiBuffer[getPort()]->getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getName -- returns the name of the port. +// returns "" if no name. Name is valid until all instances +// of MIDI classes are. +// + +const char* MidiInPort_alsa05::getName(void) { + if (getPort() == -1) { + return "Null ALSA MIDI Input"; + } + return getInputName(getPort()); +} + + +const char* MidiInPort_alsa05::getName(int i) { + return getInputName(i); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_alsa05::getNumPorts(void) { + return getNumInputs(); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_alsa05::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_alsa05::getPortStatus(void) { + return is_open_in(0); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_alsa05::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_alsa05::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_alsa05::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::insert +// + +void MidiInPort_alsa05::insert(const MidiMessage& aMessage) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa05::installSysex(uchar* anArray, int aSize) { + if (getPort() == -1) { + return -1; + } else { + return installSysexPrivate(getPort(), anArray, aSize); + } +} + +////////////////////////////// +// +// MidiInPort_alsa05::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_alsa05::installSysexPrivate(int port, uchar* anArray, int aSize) { + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i& temp = *midiBuffer[getPort()]; + return temp[index]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_alsa05::open(void) { + if (getPort() == -1) return 0; + + return Sequencer_alsa05::open(); + pauseQ[getPort()] = 0; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keeps the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_alsa05::pause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_alsa05::setBufferSize(int aSize) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setChannelOffset -- sets the MIDI chan offset, +// either 0 or 1. +// + +void MidiInPort_alsa05::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + cout << "Error: Channel offset can be only 0 or 1." << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setPort -- +// + +void MidiInPort_alsa05::setPort(int aPort) { +// if (aPort == -1) return; + if (aPort < -1 || aPort >= getNumPorts()) { + cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_alsa05::setTrace(int aState) { + if (getPort() == -1) return -1; + + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_alsa05::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_alsa05::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_alsa05::unpause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_alsa05::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_alsa05::deinitialize(void) { + closeAll(); + + for (int i=0; i*[numDevices]; + + // allocate space for Midi input sysex buffer write indices + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + } + sysexWriteBuffer = new int[numDevices]; + + // allocate space for Midi input sysex buffers + if (sysexBuffers != NULL) { + cout << "Error: memory leak on sysex buffers initialization" << endl; + exit(1); + } + sysexBuffers = new Array*[numDevices]; + + int flag; + midiInThread.setSize(getNumPorts()); + threadinitport.setSize(getNumPorts()); + // initialize the static arrays + for (int i=0; i; + midiBuffer[i]->setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + threadinitport[i] = i; + flag = pthread_create(&midiInThread[i], NULL, + interpretMidiInputStreamPrivateALSA05, &threadinitport[i]); + if (flag == -1) { + cout << "Unable to create MIDI input thread." << endl; + exit(1); + } + } + + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// friendly functions +// + + +////////////////////////////// +// +// interpretMidiInputStreamPrivateALSA05 -- handles the MIDI input stream +// for the various input devices from the ALSA MIDI driver. +// +// Note about system exclusive messages: +// System Exclusive messages are stored in a separate buffer from +// Other Midi messages since they can be variable in length. If +// The Midi Input returns a message with command byte 0xf0, then +// the p1() byte indicates the system exclusive buffer number that is +// holding the system exclusive data for that Midi message. There +// are 128 system exclusive buffers that are numbered between +// 0 and 127. These buffers are filled in a cycle. +// To extract a System exclusive message from MidiInPort_alsa05, +// you first will receive a Message with a command byte of 0xf0. +// you can then access the data for that sysex by the command: +// MidiInPort_alsa05::getSysex(buffer_number), this will return +// a pointer to the beginning of the sysex data. The first byte +// of the sysex data should be 0xf0, and the last byte of the data +// is 0xf7. All other bytes of data should be in the range from +// 0 to 127. You can also get the size of the sysex buffer by the +// following command: MidiInPort_alsa05::getSysexSize(buffer_number). +// This command will tell you the number of bytes in the system +// exclusive message including the starting 0xf0 and the ending 0xf7. +// +// If you want to minimize memory useage of the system exclusive +// buffers you can run the command: +// MidiInPort_alsa05::clearSysex(buffer_number); Otherwise the sysex +// buffer will be erased automatically the next time that the that +// buffer number is cycled through when receiving more system exclusives. +// Allocated the allocated size of the system exclusive storage will +// not be adjusted when the computer replaces the system exclusive +// message unless more storage size is needed, clearSysex however, +// will resize the sysex buffer to its default size (currently 32 bytes). +// clearSysex() without arguments will resize all buffers so that +// they are allocated to the default size and will erase data from +// all buffers. You can spoof a system exclusive message coming in +// by installing a system exclusive message and then inserting +// the system message command into the input buffer of the MidiInPort +// class, int sysex_buffer = MidiInPort_alsa05::installSysex( +// uchar *data, int size); will put the data into a sysex buffer and +// return the buffer number that it was placed into. +// +// This function assumes that System Exclusive messages cannot be sent +// as a running status messages. +// +// Note about MidiMessage time stamps: +// The MidiMessage::time field is a recording of the time that the +// first byte of the MidiMessage arrived. If the message is from +// running status mode, then the time that the first parameter byte +// arrived is stored. System exclusive message arrival times are +// recoreded at the time of the last byte (0xf7) arriving. This is +// because other system messages can be coming in while the sysex +// message is coming in. Anyway, sysex messages are not really to +// be used for real time MIDI messaging, so the exact moment that the +// first byte of the sysex came in is not important to me. +// +// + +void *interpretMidiInputStreamPrivateALSA05(void * arg) { + int portToWatch = *(int*)arg; + + int* argsExpected = NULL; // MIDI parameter bytes expected to follow + int* argsLeft = NULL; // MIDI parameter bytes left to wait for + uchar packet[1]; // bytes for sequencer driver + MidiMessage* message = NULL; // holder for current MIDI message + int newSigTime = 0; // for millisecond timer + int lastSigTime = -1; // for millisecond timer + int zeroSigTime = -1; // for timing incoming events + int device = -1; // for sorting out the bytes by input device + Array* sysexIn; // MIDI Input sysex temporary storage + + // Note on the use of argsExpected and argsLeft for sysexs: + // If argsExpected is -1, then a sysex message is coming in. + // If argsLeft < 0, then the sysex message has not finished comming + // in. If argsLeft == 0 and argsExpected == -1, then the sysex + // has finished coming in and is to be sent to the correct + // location. + + // allocate space for MIDI messages, each device has a different message + // holding spot in case the messages overlap in the input stream + message = new MidiMessage[MidiInPort_alsa05::numDevices]; + argsExpected = new int[MidiInPort_alsa05::numDevices]; + argsLeft = new int[MidiInPort_alsa05::numDevices]; + + sysexIn = new Array[MidiInPort_alsa05::numDevices]; + for (int j=0; j= 0) { + argsLeft[device] = argsExpected[device]; + } + + newSigTime = MidiInPort_alsa05::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + + if (packet[0] != 0xf7) { + message[device].p0() = packet[0]; + } + message[device].p1() = 0; + message[device].p2() = 0; + message[device].p3() = 0; + + if (packet[0] == 0xf7) { + goto sysex_done; + } + } else if (argsLeft[device]) { // not a command byte coming in + if (message[device].time == 0) { + // store the receipt time of the first message byte + newSigTime = MidiInPort_alsa05::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + } + + if (argsExpected[device] < 0) { + // continue processing a sysex message + sysexIn[device].append(packet[0]); + } else { + // handle a message other than a sysex message + if (argsLeft[device] == argsExpected[device]) { + message[device].p1() = packet[0]; + } else { + message[device].p2() = packet[0]; + } + argsLeft[device]--; + } + + // if MIDI message is complete, setup for running status, and + // insert note into proper buffer. + + if (argsExpected[device] >= 0 && !argsLeft[device]) { + + // store parameter data for running status + switch (message[device].p0() & 0xf0) { + case 0xc0: argsLeft[device] = 1; break; + case 0xd0: argsLeft[device] = 1; break; // fix by dan + default: argsLeft[device] = 2; break; + // 0x80 expects two arguments + // 0x90 expects two arguments + // 0xa0 expects two arguments + // 0xb0 expects two arguments + // 0xe0 expects two arguments + } + + lastSigTime = newSigTime; + + sysex_done: // come here when a sysex is completely done + + // insert the MIDI message into the appropriate buffer + // do not insert into buffer if the MIDI input device + // is paused (which can mean closed). Or if the + // pauseQ array is pointing to NULL (which probably means that + // things are about to shut down). + if (MidiInPort_alsa05::pauseQ != NULL && + MidiInPort_alsa05::pauseQ[device] == 0) { + if (argsExpected[device] < 0) { + // store the sysex in the MidiInPort_alsa05 + // buffer for sysexs and return the storage + // location: + int sysexlocation = + MidiInPort_alsa05::installSysexPrivate(device, + sysexIn[device].getBase(), + sysexIn[device].getSize()); + + message[device].p0() = 0xf0; + message[device].p1() = sysexlocation; + + sysexIn[device].setSize(0); // empty the sysex storage + argsExpected[device] = 0; // no run status for sysex + argsLeft[device] = 0; // turn off sysex input flag + } + MidiInPort_alsa05::midiBuffer[device]->insert( + message[device]); +// if (MidiInPort_alsa05::callbackFunction != NULL) { +// MidiInPort_alsa05::callbackFunction(device); +// } + if (MidiInPort_alsa05::trace[device]) { + cout << '[' << hex << (int)message[device].p0() + << ':' << dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << flush; + } + message[device].time = 0; + } else { + if (MidiInPort_alsa05::trace[device]) { + cout << '[' << hex << (int)message[device].p0() + << 'P' << dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << flush; + } + } + } + } + + } // end while (1) + + // This code is not yet reached, but should be made to do so eventually + + if (message != NULL) { + delete message; + message = NULL; + } + + if (argsExpected != NULL) { + delete argsExpected; + argsExpected = NULL; + } + + if (argsLeft != NULL) { + delete argsLeft; + argsLeft = NULL; + } + + if (sysexIn != NULL) { + delete sysexIn; + sysexIn = NULL; + } + + + return NULL; +} + + + +#endif /* LINUX and ALSA05 */ + + + +// md5sum: cc5ea6a6078cb534fc6c39543aa57a83 - MidiInPort_alsa05.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_linux.cpp b/src/midiio/src/MidiInPort_linux.cpp new file mode 100644 index 0000000..01274e2 --- /dev/null +++ b/src/midiio/src/MidiInPort_linux.cpp @@ -0,0 +1,491 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun May 14 22:35:27 PDT 2000 +// Last Modified: Thu May 18 23:36:00 PDT 2000 +// Last Modified: Sat Nov 2 20:37:49 PST 2002 (added ifdef ALSA OSS) +// Filename: ...sig/maint/code/control/MidiInPort/MidiInPort_linux.cpp +// Web Address: http://sig.sapp.org/include/sig/MidiInPort_linux.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of an +// operating-system specific MIDI input method. +// Provides control of all low-level MIDI input +// functionality such that it will work on all +// computers in the same manner. +// + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#include +#include +#include "MidiInPort_linux.h" + + +// initialize static variables oss_input->close(); break; +int MidiInPort_linux::objectCount = 0; +int MidiInPort_linux::current = MIDI_IN_OSS_SELECT; +int MidiInPort_linux::alsaQ = 0; +int MidiInPort_linux::ossQ = 0; +MidiInPort_oss *MidiInPort_linux::oss_input = NULL; +MidiInPort_alsa *MidiInPort_linux::alsa_input = NULL; +MidiInPort_unsupported *MidiInPort_linux::unknown_input = NULL; + + +MidiInPort_linux::MidiInPort_linux(void) { + if (objectCount == 0) { + determineDrivers(); + } else if (objectCount < 0) { + cout << "Error: unusual MidiInPort_linux object count" << endl; + exit(1); + } + + objectCount++; +} + + +MidiInPort_linux::MidiInPort_linux(int aPort, int autoOpen = 1) { + if (objectCount == 0) { + determineDrivers(); + setAndOpenPort(aPort); + } else if (objectCount < 0) { + cout << "Error: unusual MidiInPort_linux object count" << endl; + exit(1); + } + + objectCount++; +} + + +MidiInPort_linux::~MidiInPort_linux() { + objectCount--; + if (objectCount == 0) { + if (oss_input != NULL) { + delete oss_input; + oss_input = NULL; + } + if (alsa_input != NULL) { + delete alsa_input; + alsa_input = NULL; + } + if (unknown_input != NULL) { + delete unknown_input; + unknown_input = NULL; + } + } + + if (objectCount < 0) { + cout << "Error: unusual MidiOutPort_linux count when destructing" << endl; + exit(1); + } +} + + +void MidiInPort_linux::clearSysex(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->clearSysex(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->clearSysex(); break; + default: unknown_input->clearSysex(); break; + } +} + + +void MidiInPort_linux::clearSysex(int buffer) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->clearSysex(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->clearSysex(); break; + default: unknown_input->clearSysex(); break; + } +} + + +void MidiInPort_linux::close(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->close(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->close(); break; + default: unknown_input->close(); break; + } +} + + +void MidiInPort_linux::closeAll(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->closeAll(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->closeAll(); break; + default: unknown_input->closeAll(); break; + } +} + + +MidiMessage MidiInPort_linux::extract(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->extract(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->extract(); break; + default: return unknown_input->extract(); break; + } +} + + +int MidiInPort_linux::getBufferSize(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getBufferSize(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getBufferSize(); break; + default: return unknown_input->getBufferSize(); break; + } +} + + +int MidiInPort_linux::getChannelOffset(void) const { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getChannelOffset(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getChannelOffset(); break; + default: return unknown_input->getChannelOffset(); break; + } +} + + +int MidiInPort_linux::getCount(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getCount(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getCount(); break; + default: return unknown_input->getCount(); break; + } +} + + +const char* MidiInPort_linux::getName(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getName(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getName(); break; + default: return unknown_input->getName(); break; + } +} + + +const char* MidiInPort_linux::getName(int i) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getName(i); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getName(i); break; + default: return unknown_input->getName(i); break; + } +} + + +int MidiInPort_linux::getNumPorts(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getNumPorts(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getNumPorts(); break; + default: return unknown_input->getNumPorts(); break; + } +} + + +int MidiInPort_linux::getPort(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getPort(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getPort(); break; + default: return unknown_input->getPort(); break; + } +} + + +int MidiInPort_linux::getPortStatus(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getPortStatus(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getPortStatus(); break; + default: return unknown_input->getPortStatus(); break; + } +} + + +uchar* MidiInPort_linux::getSysex(int buffer) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getSysex(buffer); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getSysex(buffer); break; + default: return unknown_input->getSysex(buffer); break; + } +} + + +int MidiInPort_linux::getSysexSize(int buffer) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getSysexSize(buffer); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getSysexSize(buffer); break; + default: return unknown_input->getSysexSize(buffer); break; + } +} + + +int MidiInPort_linux::getTrace(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->getTrace(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->getTrace(); break; + default: return unknown_input->getTrace(); break; + } +} + + +void MidiInPort_linux::insert(const MidiMessage& aMessage) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->insert(aMessage); break; + case MIDI_IN_ALSA_SELECT: alsa_input->insert(aMessage); break; + default: unknown_input->insert(aMessage); break; + } +} + + +int MidiInPort_linux::installSysex(uchar* anArray, int aSize) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: + return oss_input->installSysex(anArray, aSize); + break; + case MIDI_IN_ALSA_SELECT: + return alsa_input->installSysex(anArray, aSize); + break; + default: + return unknown_input->installSysex(anArray, aSize); + break; + } +} + + +MidiMessage& MidiInPort_linux::message(int index) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->message(index); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->message(index); break; + default: return unknown_input->message(index); break; + } +} + +int MidiInPort_linux::open(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->open(); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->open(); break; + default: return unknown_input->open(); break; + } +} + + +MidiMessage& MidiInPort_linux::operator[](int index) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->message(index); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->message(index); break; + default: return unknown_input->message(index); break; + } +} + + +void MidiInPort_linux::pause(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->pause(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->pause(); break; + default: unknown_input->pause(); break; + } +} + + +void MidiInPort_linux::setBufferSize(int aSize) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->setBufferSize(aSize); break; + case MIDI_IN_ALSA_SELECT: alsa_input->setBufferSize(aSize); break; + default: unknown_input->setBufferSize(aSize); break; + } +} + + +void MidiInPort_linux::setChannelOffset(int anOffset) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->setChannelOffset(anOffset); break; + case MIDI_IN_ALSA_SELECT: alsa_input->setChannelOffset(anOffset); break; + default: unknown_input->setChannelOffset(anOffset); break; + } +} + + +void MidiInPort_linux::setAndOpenPort(int aPort) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: + oss_input->setPort(aPort); + oss_input->open(); + break; + case MIDI_IN_ALSA_SELECT: + alsa_input->setPort(aPort); + alsa_input->open(); + break; + default: + unknown_input->setPort(aPort); + unknown_input->open(); + break; + } +} + + +void MidiInPort_linux::setPort(int aPort) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->setPort(aPort); break; + case MIDI_IN_ALSA_SELECT: alsa_input->setPort(aPort); break; + default: unknown_input->setPort(aPort); break; + } +} + + +int MidiInPort_linux::setTrace(int aState) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: return oss_input->setTrace(aState); break; + case MIDI_IN_ALSA_SELECT: return alsa_input->setTrace(aState); break; + default: return unknown_input->setTrace(aState); break; + } +} + + +void MidiInPort_linux::toggleTrace(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->toggleTrace(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->toggleTrace(); break; + default: unknown_input->toggleTrace(); break; + } +} + + +void MidiInPort_linux::unpause(void) { + switch (getSelect()) { + case MIDI_IN_OSS_SELECT: oss_input->unpause(); break; + case MIDI_IN_ALSA_SELECT: alsa_input->unpause(); break; + default: unknown_input->unpause(); break; + } +} + + + +////////////////////////////// +// +// MidiInPort_linux::getSelect -- return the type of MIDI which +// is being used to send MIDI output. +// + +int MidiInPort_linux::getSelect(void) { + return current; +} + + +////////////////////////////// +// +// MidiInPort_linux::selectOSS -- select the OSS MIDI output +// returns 1 if OSS is available, otherwise returns 0. +// + +int MidiInPort_linux::selectOSS(void) { + if (ossQ) { + current = MIDI_IN_OSS_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_linux::selectALSA -- select the ALSA MIDI output +// returns 1 if ALSA is available, otherwise returns 0. +// + +int MidiInPort_linux::selectALSA(void) { + if (alsaQ) { + current = MIDI_IN_ALSA_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_linux::selectUnknown -- select the Unknown MIDI output +// returns 1 always. +// + +int MidiInPort_linux::selectUnknown(void) { + current = MIDI_IN_UNKNOWN_SELECT; + return 1; +} + + +////////////////////////////////////////////////////////////////////////// +// +// Private Functions +// + +////////////////////////////// +// +// MidiInPort_linux::determineDrivers -- see if OSS/ALSA are +// available. If /dev/sequencer is present, assume that OSS is +// available. If /dev/snd/sdq is present, assume that ALSA is +// available. +// + +void MidiInPort_linux::determineDrivers(void) { + struct stat filestats; + int status; + status = stat("/dev/sequencer", &filestats); + + if (status != 0) { + ossQ = 0; + } else { + ossQ = 1; + } + + status = stat("/dev/snd/seq", &filestats); + + if (status != 0) { + alsaQ = 0; + } else { + alsaQ = 1; + } + + + current = MIDI_IN_UNKNOWN_SELECT; + + if (ossQ) { + current = MIDI_IN_OSS_SELECT; + } + + if (alsaQ) { + current = MIDI_IN_ALSA_SELECT; + } + + // create MIDI output types which are available: + + if (oss_input != NULL) { + delete oss_input; + oss_input = NULL; + } + if (alsa_input != NULL) { + delete alsa_input; + alsa_input = NULL; + } + if (unknown_input != NULL) { + delete unknown_input; + unknown_input = NULL; + } + + if (ossQ) { + oss_input = new MidiInPort_oss; + } + if (alsaQ) { + alsa_input = new MidiInPort_alsa; + } + + unknown_input = new MidiInPort_unsupported; + +} + + +#endif /* ALSA and OSS */ +#endif /* LINUX */ + + +// md5sum: d634dd5c3b7e8c4d75b99d7459c3f073 - MidiInPort_linux.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_oss.cpp b/src/midiio/src/MidiInPort_oss.cpp new file mode 100644 index 0000000..d16c865 --- /dev/null +++ b/src/midiio/src/MidiInPort_oss.cpp @@ -0,0 +1,1036 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998 +// Last Modified: Sat Jan 9 06:05:24 PST 1999 +// Last Modified: Tue Jun 29 16:18:45 PDT 1999 (added sysex capability) +// Last Modified: Mon Dec 6 16:28:45 PST 1999 +// Last Modified: Wed Jan 12 10:59:33 PST 2000 (orphan 0xf0 behavior change) +// Last Modified: Wed May 10 17:10:05 PDT 2000 (name change from _linux to _oss) +// Last Modified: Fri Oct 26 14:41:36 PDT 2001 (running status for 0xa0 and 0xd0 +// fixed by Daniel Gardner) +// Filename: ...sig/code/control/MidiInPort/linux/MidiInPort_oss.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInPort_oss.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// linux OSS sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// + +#ifdef LINUX + +#include "MidiInPort_oss.h" +#include +#include +#include +#include + + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables + +int MidiInPort_oss::numDevices = 0; +int MidiInPort_oss::objectCount = 0; +int* MidiInPort_oss::portObjectCount = NULL; +CircularBuffer** MidiInPort_oss::midiBuffer = NULL; +int MidiInPort_oss::channelOffset = 0; +SigTimer MidiInPort_oss::midiTimer; +int* MidiInPort_oss::pauseQ = NULL; +int* MidiInPort_oss::trace = NULL; +std::ostream* MidiInPort_oss::tracedisplay = &std::cout; +pthread_t MidiInPort_oss::midiInThread; +int* MidiInPort_oss::sysexWriteBuffer = NULL; +Array** MidiInPort_oss::sysexBuffers = NULL; + + + +////////////////////////////// +// +// MidiInPort_oss::MidiInPort_oss +// default values: autoOpen = 1 +// + +MidiInPort_oss::MidiInPort_oss(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_oss::MidiInPort_oss(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::~MidiInPort_oss +// + +MidiInPort_oss::~MidiInPort_oss() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiInPort_oss object count!: " + << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_oss::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_oss::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::close +// + +void MidiInPort_oss::close(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_oss::closeAll -- +// + +void MidiInPort_oss::closeAll(void) { + Sequencer_oss::close(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::extract -- returns the next MIDI message +// received since that last extracted message. +// + +MidiMessage MidiInPort_oss::extract(void) { + if (getPort() == -1) { + MidiMessage temp; + return temp; + } + + return midiBuffer[getPort()]->extract(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getBufferSize -- returns the maximum possible number +// of MIDI messages that can be stored in the buffer +// + +int MidiInPort_oss::getBufferSize(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getSize(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiInPort_oss::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiInPort_oss::getCount -- returns the number of unexamined +// MIDI messages waiting in the input buffer. +// + +int MidiInPort_oss::getCount(void) { + if (getPort() == -1) return 0; + + return midiBuffer[getPort()]->getCount(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getName -- returns the name of the port. +// returns "" if no name. Name is valid until all instances +// of MIDI classes are. +// + +const char* MidiInPort_oss::getName(void) { + if (getPort() == -1) { + return "Null OSS MIDI Input"; + } + return getInputName(getPort()); +} + + +const char* MidiInPort_oss::getName(int i) { + return getInputName(i); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_oss::getNumPorts(void) { + return getNumInputs(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_oss::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_oss::getPortStatus -- 0 if closed, 1 if open +// + +int MidiInPort_oss::getPortStatus(void) { + return is_open(); +} + + + +////////////////////////////// +// +// MidiInPort_oss::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_oss::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_oss::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_oss::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_oss::insert +// + +void MidiInPort_oss::insert(const MidiMessage& aMessage) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->insert(aMessage); +} + + + +////////////////////////////// +// +// MidiInPort_oss::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_oss::installSysex(uchar* anArray, int aSize) { + if (getPort() == -1) { + return -1; + } else { + return installSysexPrivate(getPort(), anArray, aSize); + } +} + +////////////////////////////// +// +// MidiInPort_oss::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_oss::installSysexPrivate(int port, uchar* anArray, int aSize) { + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i& temp = *midiBuffer[getPort()]; + return temp[index]; +} + + + +////////////////////////////// +// +// MidiInPort_oss::open -- returns true if MIDI input port was +// opened. +// + +int MidiInPort_oss::open(void) { + if (getPort() == -1) return 0; + + return Sequencer_oss::open(); + pauseQ[getPort()] = 0; +} + + + +////////////////////////////// +// +// MidiInPort_oss::pause -- stop the Midi input port from +// inserting MIDI messages into the buffer, but keeps the +// port open. Use unpause() to reverse the effect of pause(). +// + +void MidiInPort_oss::pause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 1; +} + + + +////////////////////////////// +// +// MidiInPort_oss::setBufferSize -- sets the allocation +// size of the MIDI input buffer. +// + +void MidiInPort_oss::setBufferSize(int aSize) { + if (getPort() == -1) return; + + midiBuffer[getPort()]->setSize(aSize); +} + + + +////////////////////////////// +// +// MidiInPort_oss::setChannelOffset -- sets the MIDI chan offset, +// either 0 or 1. +// + +void MidiInPort_oss::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::setPort +// + +void MidiInPort_oss::setPort(int aPort) { +// if (aPort == -1) return; + if (aPort < -1 || aPort >= getNumPorts()) { +// std::cerr << "Error: maximum port number is: " << getNumPorts()-1 +// << ", but you tried to access port: " << aPort << std::endl; +// exit(1); + } + else { + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } + } +} + + + +////////////////////////////// +// +// MidiInPort_oss::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_oss::setTrace(int aState) { + if (getPort() == -1) return -1; + + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_oss::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_oss::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiInPort_oss::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_oss::unpause(void) { + if (getPort() == -1) return; + + pauseQ[getPort()] = 0; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_oss::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_oss::deinitialize(void) { + closeAll(); + + for (int i=0; i*[numDevices]; + + // allocate space for Midi input sysex buffer write indices + if (sysexWriteBuffer != NULL) { + delete [] sysexWriteBuffer; + } + sysexWriteBuffer = new int[numDevices]; + + // allocate space for Midi input sysex buffers + if (sysexBuffers != NULL) { + std::cout << "Error: memory leak on sysex buffers initialization" << std::endl; + exit(1); + } + sysexBuffers = new Array*[numDevices]; + + // initialize the static arrays + for (int i=0; i; + midiBuffer[i]->setSize(DEFAULT_INPUT_BUFFER_SIZE); + + sysexWriteBuffer[i] = 0; + sysexBuffers[i] = new Array[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + } + + int flag = pthread_create(&midiInThread, NULL, + interpretMidiInputStreamPrivate, NULL); + if (flag == -1) { + std::cout << "Unable to create MIDI input thread." << std::endl; + exit(1); + } + + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// friendly functions +// + + +////////////////////////////// +// +// interpretMidiInputStreamPrivate -- handles the MIDI input stream +// for the various input devices. +// +// Note about system exclusive messages: +// System Exclusive messages are stored in a separate buffer from +// Other Midi messages since they can be variable in length. If +// The Midi Input returns a message with command byte 0xf0, then +// the p1() byte indicates the system exclusive buffer number that is +// holding the system exclusive data for that Midi message. There +// are 128 system exclusive buffers that are numbered between +// 0 and 127. These buffers are filled in a cycle. +// To extract a System exclusive message from MidiInPort_oss, +// you first will receive a Message with a command byte of 0xf0. +// you can then access the data for that sysex by the command: +// MidiInPort_oss::getSysex(buffer_number), this will return +// a pointer to the beginning of the sysex data. The first byte +// of the sysex data should be 0xf0, and the last byte of the data +// is 0xf7. All other bytes of data should be in the range from +// 0 to 127. You can also get the size of the sysex buffer by the +// following command: MidiInPort_oss::getSysexSize(buffer_number). +// This command will tell you the number of bytes in the system +// exclusive message including the starting 0xf0 and the ending 0xf7. +// +// If you want to minimize memory useage of the system exclusive +// buffers you can run the command: +// MidiInPort_oss::clearSysex(buffer_number); Otherwise the sysex +// buffer will be erased automatically the next time that the that +// buffer number is cycled through when receiving more system exclusives. +// Allocated the allocated size of the system exclusive storage will +// not be adjusted when the computer replaces the system exclusive +// message unless more storage size is needed, clearSysex however, +// will resize the sysex buffer to its default size (currently 32 bytes). +// clearSysex() without arguments will resize all buffers so that +// they are allocated to the default size and will erase data from +// all buffers. You can spoof a system exclusive message coming in +// by installing a system exclusive message and then inserting +// the system message command into the input buffer of the MidiInPort +// class, int sysex_buffer = MidiInPort_oss::installSysex( +// uchar *data, int size); will put the data into a sysex buffer and +// return the buffer number that it was placed into. +// +// This function assumes that System Exclusive messages cannot be sent +// as a running status messages. +// +// Note about MidiMessage time stamps: +// The MidiMessage::time field is a recording of the time that the +// first byte of the MidiMessage arrived. If the message is from +// running status mode, then the time that the first parameter byte +// arrived is stored. System exclusive message arrival times are +// recoreded at the time of the last byte (0xf7) arriving. This is +// because other system messages can be coming in while the sysex +// message is coming in. Anyway, sysex messages are not really to +// be used for real time MIDI messaging, so the exact moment that the +// first byte of the sysex came in is not important to me. +// +// + +void *interpretMidiInputStreamPrivate(void *) { + + int* argsExpected = NULL; // MIDI parameter bytes expected to follow + int* argsLeft = NULL; // MIDI parameter bytes left to wait for + uchar packet[4]; // bytes for sequencer driver + MidiMessage* message = NULL; // holder for current MIDI message + int newSigTime = 0; // for millisecond timer + int lastSigTime = -1; // for millisecond timer + int zeroSigTime = -1; // for timing incoming events + int device = -1; // for sorting out the bytes by input device + Array* sysexIn; // MIDI Input sysex temporary storage + + // Note on the use of argsExpected and argsLeft for sysexs: + // If argsExpected is -1, then a sysex message is coming in. + // If argsLeft < 0, then the sysex message has not finished comming + // in. If argsLeft == 0 and argsExpected == -1, then the sysex + // has finished coming in and is to be sent to the correct + // location. + + static int count = 0; + if (count != 0) { + std::cerr << "Cannot run this function more than once" << std::endl; + exit(1); + } else { + // allocate space for MIDI messages, each device has a different message + // holding spot in case the messages overlap in the input stream + message = new MidiMessage[MidiInPort_oss::numDevices]; + argsExpected = new int[MidiInPort_oss::numDevices]; + argsLeft = new int[MidiInPort_oss::numDevices]; + + sysexIn = new Array[MidiInPort_oss::numDevices]; + for (int j=0; j= 0) { + argsLeft[device] = argsExpected[device]; + } + + newSigTime = MidiInPort_oss::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + + if (packet[1] != 0xf7) { + message[device].p0() = packet[1]; + } + message[device].p1() = 0; + message[device].p2() = 0; + message[device].p3() = 0; + + if (packet[1] == 0xf7) { + goto sysex_done; + } + } else if (argsLeft[device]) { // not a command byte coming in + if (message[device].time == 0) { + // store the receipt time of the first message byte + newSigTime = MidiInPort_oss::midiTimer.getTime(); + message[device].time = newSigTime - zeroSigTime; + } + + if (argsExpected[device] < 0) { + // continue processing a sysex message + sysexIn[device].append(packet[1]); + } else { + // handle a message other than a sysex message + if (argsLeft[device] == argsExpected[device]) { + message[device].p1() = packet[1]; + } else { + message[device].p2() = packet[1]; + } + argsLeft[device]--; + } + + // if MIDI message is complete, setup for running status, and + // insert note into proper buffer. + + if (argsExpected[device] >= 0 && !argsLeft[device]) { + + // store parameter data for running status + switch (message[device].p0() & 0xf0) { + case 0xc0: argsLeft[device] = 1; break; + case 0xd0: argsLeft[device] = 1; break; // fix by dan + default: argsLeft[device] = 2; break; + // 0x80 expects two arguments + // 0x90 expects two arguments + // 0xa0 expects two arguments + // 0xb0 expects two arguments + // 0xe0 expects two arguments + } + + lastSigTime = newSigTime; + + sysex_done: // come here when a sysex is completely done + + // insert the MIDI message into the appropriate buffer + // do not insert into buffer if the MIDI input device + // is paused (which can mean closed). Or if the + // pauseQ array is pointing to NULL (which probably means that + // things are about to shut down). + if (MidiInPort_oss::pauseQ != NULL && + MidiInPort_oss::pauseQ[device] == 0) { + if (argsExpected[device] < 0) { + // store the sysex in the MidiInPort_oss + // buffer for sysexs and return the storage + // location: + int sysexlocation = + MidiInPort_oss::installSysexPrivate(device, + sysexIn[device].getBase(), + sysexIn[device].getSize()); + + message[device].p0() = 0xf0; + message[device].p1() = sysexlocation; + + sysexIn[device].setSize(0); // empty the sysex storage + argsExpected[device] = 0; // no run status for sysex + argsLeft[device] = 0; // turn off sysex input flag + } + MidiInPort_oss::midiBuffer[device]->insert( + message[device]); +// if (MidiInPort_oss::callbackFunction != NULL) { +// MidiInPort_oss::callbackFunction(device); +// } + if (MidiInPort_oss::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << ':' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + message[device].time = 0; + } else { + if (MidiInPort_oss::trace[device]) { + std::cout << '[' << std::hex << (int)message[device].p0() + << 'P' << std::dec << (int)message[device].p1() + << ',' << (int)message[device].p2() << ']' + << std::flush; + } + } + } + } + break; + + default: + break; + } // end switch + } // end while (1) + + // This code is not yet reached, but should be made to do so eventually + + if (message != NULL) { + delete message; + message = NULL; + } + + if (argsExpected != NULL) { + delete argsExpected; + argsExpected = NULL; + } + + if (argsLeft != NULL) { + delete argsLeft; + argsLeft = NULL; + } + + if (sysexIn != NULL) { + delete sysexIn; + sysexIn = NULL; + } + +} + + + +#endif // LINUX + + + +// md5sum: 2008f4a298bef0cd85620a5507815866 - MidiInPort_oss.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_unsupported.cpp b/src/midiio/src/MidiInPort_unsupported.cpp new file mode 100644 index 0000000..584a468 --- /dev/null +++ b/src/midiio/src/MidiInPort_unsupported.cpp @@ -0,0 +1,487 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998 +// Last Modified: Thu Jan 22 22:53:53 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:42:59 PDT 1999 (added sysex capability) +// Filename: ...sig/code/control/MidiInPort/unsupported/MidiInPort_unsupported.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiInPort_unsupported.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// an unknown sound driver's specific MIDI input methods. +// This class is inherited privately by the MidiInPort class. +// This class is used when there is no MIDI input, so +// that MIDI programs can otherwise be compiled and run. +// This file can also serve as a template for creating +// an OS specific class for MIDI input. +// + +#include "MidiInPort_unsupported.h" +#include +#include + + +#define DEFAULT_INPUT_BUFFER_SIZE (1024) + +// initialized static variables +int MidiInPort_unsupported::numDevices = 0; +int MidiInPort_unsupported::objectCount = 0; +int* MidiInPort_unsupported::openQ = NULL; +int* MidiInPort_unsupported::portObjectCount = NULL; +CircularBuffer* MidiInPort_unsupported::midiBuffer = NULL; +int MidiInPort_unsupported::channelOffset = 0; +int* MidiInPort_unsupported::sysexWriteBuffer = NULL; +Array** MidiInPort_unsupported::sysexBuffers = NULL; + + +////////////////////////////// +// +// MidiInPort_unsupported::MidiInPort_unsupported +// default values: autoOpen = 1 +// + +MidiInPort_unsupported::MidiInPort_unsupported(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiInPort_unsupported::MidiInPort_unsupported(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::~MidiInPort_unsupported +// + +MidiInPort_unsupported::~MidiInPort_unsupported() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiInPort_unsupported object count!: " + << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::close +// + +void MidiInPort_unsupported::close(void) { + if (getPortStatus() == 1) { + openQ[getPort()] = 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::closeAll +// + +void MidiInPort_unsupported::closeAll(void) { + for (int i=0; i= getNumPorts()) { + std::cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + portObjectCount[port]++; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_unsupported::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_unsupported::toggleTrace(void) { + trace = !trace; +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_unsupported::unpause(void) { + // nothing +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_unsupported::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_unsupported::deinitialize(void) { + int deviceCount = numDevices; + closeAll(); + + if (sysexBuffers != NULL) { + for (int i=0; i*[numDevices]; + + // allocate space for sysexWriteBuffer, the port open/close status + if (sysexWriteBuffer != NULL) delete [] sysexWriteBuffer; + sysexWriteBuffer = new int[numDevices]; + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for the Midi input buffers + if (midiBuffer != NULL) delete [] midiBuffer; + midiBuffer = new CircularBuffer[numDevices]; + + // initialize the static arrays + for (int i=0; i[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + } +} + + + +////////////////////////////// +// +// MidiInPort_unsupported::setPortStatus +// + +void MidiInPort_unsupported::setPortStatus(int aStatus) { + if (aStatus) { + openQ[getPort()] = 1; + } else { + openQ[getPort()] = 0; + } +} + + +// md5sum: d8b8f65af70a9b3c33e62794c2a4a91e - MidiInPort_unsupported.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInPort_visual.cpp b/src/midiio/src/MidiInPort_visual.cpp new file mode 100644 index 0000000..b4659bf --- /dev/null +++ b/src/midiio/src/MidiInPort_visual.cpp @@ -0,0 +1,1267 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed Jan 21 22:46:30 GMT-0800 1998 +// Last Modified: Wed Jun 30 11:29:51 PDT 1999 (added sysex capability) +// Last Modified: Wed Oct 13 10:18:22 PDT 1999 (midiInUnprepareHeader change) +// Last Modified: Tue Nov 23 15:01:17 PST 1999 (fixed sysex NULL init) +// Filename: ...sig/code/control/MidiInPort/visual/MidiInPort_visual.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiInPort_visual.cpp +// Syntax: C++ +// +// Description: An interface for MIDI input capabilities of +// Windows 95/NT/98 specific MIDI input methods. +// as defined in winmm.lib. This class is inherited +// privately by the MidiInPort class. +// + +#ifdef VISUAL + + +#include "MidiInPort_visual.h" + +#include +#include + +#include + + +// initialized static variables +int MidiInPort_visual::numDevices = 0; +int MidiInPort_visual::objectCount = 0; +int* MidiInPort_visual::openQ = NULL; +int* MidiInPort_visual::inrunningQ = NULL; +int* MidiInPort_visual::portObjectCount = NULL; +HMIDIIN* MidiInPort_visual::device = NULL; +MIDIHDR** MidiInPort_visual::sysexDriverBuffer1 = NULL; +MIDIHDR** MidiInPort_visual::sysexDriverBuffer2 = NULL; +int* MidiInPort_visual::sysexDBnumber = NULL; +HANDLE* MidiInPort_visual::hMutex = NULL; +CircularBuffer* MidiInPort_visual::midiBuffer = NULL; +int MidiInPort_visual::channelOffset = 0; +int* MidiInPort_visual::sysexWriteBuffer = NULL; +Array** MidiInPort_visual::sysexBuffers = NULL; +int* MidiInPort_visual::sysexStatus = NULL; + + +////////////////////////////// +// +// MidiInPort_visual::MidiInPort_visual +// default values: autoOpen = 1 +// + +MidiInPort_visual::MidiInPort_visual(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + trace = 0; + port = -1; + setPort(0); +} + + +MidiInPort_visual::MidiInPort_visual(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + trace = 0; + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::~MidiInPort_visual +// + +MidiInPort_visual::~MidiInPort_visual() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + cerr << "Error: bad MidiInPort_visual object count!: " + << objectCount << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::clearSysex -- clears the data from a sysex +// message and sets the allocation size to the default size (of 32 +// bytes). +// + +void MidiInPort_visual::clearSysex(int buffer) { + buffer = 0x7f | buffer; // limit buffer range from 0 to 127 + + if (getPort() == -1) { + return; + } + + sysexBuffers[getPort()][buffer].setSize(0); + if (sysexBuffers[getPort()][buffer].getAllocSize() != 32) { + // shrink the storage buffer's size if necessary + sysexBuffers[getPort()][buffer].setAllocSize(32); + } +} + + +void MidiInPort_visual::clearSysex(void) { + // clear all sysex buffers + for (int i=0; i<128; i++) { + clearSysex(i); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::close +// + +void MidiInPort_visual::close(void) { + if (getPort() == -1) { + return; + } + if (getPortStatus() == 1 && device[getPort()] != NULL) { + midiInReset(device[getPort()]); + midiInClose(device[getPort()]); + uninstallSysexStuff(device[getPort()], port); + openQ[getPort()] = 0; + inrunningQ[getPort()] = 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::closeAll +// + +void MidiInPort_visual::closeAll(void) { + for (int i=0; i getNumPorts()) { + cerr << "Error invalid index for getName: " << i << endl; + exit(1); + } + + midiInGetDevCaps(i, &inputCapabilities, sizeof(MIDIINCAPS)); + + return inputCapabilities.szPname; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getNumPorts -- returns the number of available +// ports for MIDI input +// + +int MidiInPort_visual::getNumPorts(void) { + return midiInGetNumDevs(); +} + + + +////////////////////////////// +// +// MidiInPort_visual::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiInPort_visual::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiInPort_visual::getPortStatus -- 0 if closed, 1 if open, 2 if +// specifically not connected to any MIDI port. +// + +int MidiInPort_visual::getPortStatus(void) { + if (getPort() == -1) { + return 2; + } + + if (openQ[getPort()] == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getSysex -- returns the sysex message contents +// of a given buffer. You should check to see that the size is +// non-zero before looking at the data. The data pointer will +// be NULL if there is no data in the buffer. +// + +uchar* MidiInPort_visual::getSysex(int buffer) { + buffer &= 0x7f; // limit the buffer access to indices 0 to 127. + + if (getPort() == -1) { + return NULL; + } + + if (sysexBuffers[getPort()][buffer].getSize() < 2) { + return NULL; + } else { + return sysexBuffers[getPort()][buffer].getBase(); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getSysexSize -- returns the sysex message byte +// count of a given buffer. Buffers are in the range from +// 0 to 127. +// + +int MidiInPort_visual::getSysexSize(int buffer) { + if (getPort() == -1) { + return 0; + } else { + return sysexBuffers[getPort()][buffer & 0x7f].getSize(); + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::getTrace -- returns true if trace is on or false +// if trace is off. if trace is on, then prints to standard +// output the Midi message received. +// + +int MidiInPort_visual::getTrace(void) { + return trace; +} + + + +////////////////////////////// +// +// MidiInPort_visual::insert +// + +void MidiInPort_visual::insert(const MidiMessage& aMessage) { + waitForMutex(); + if (getPort() == -1) { + // do nothing + } else { + midiBuffer[getPort()].insert(aMessage); + } + releaseMutex(); +} + + + +////////////////////////////// +// +// MidiInPort_visual::installSysex -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_visual::installSysex(uchar* anArray, int aSize) { + return installSysexPrivate(getPort(), anArray, aSize); +} + + + +////////////////////////////// +// +// MidiInPort_visual::installSysexPrivate -- put a sysex message into a +// buffer. The buffer number that it is put into is returned. +// + +int MidiInPort_visual::installSysexPrivate(int port, uchar* anArray, int aSize){ + if (port == -1) { + return -1; + } + + // choose a buffer to install sysex data into: + int bufferNumber = sysexWriteBuffer[port]; + sysexWriteBuffer[port]++; + if (sysexWriteBuffer[port] >= 128) { + sysexWriteBuffer[port] = 0; + } + + // copy contents of sysex message into the chosen buffer + sysexBuffers[port][bufferNumber].setSize(aSize); + uchar* dataptr = sysexBuffers[port][bufferNumber].getBase(); + uchar* indataptr = anArray; + for (int i=0; i= getNumPorts()) { + cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::setTrace -- if false, then don't print MIDI messages +// to the screen. +// + +int MidiInPort_visual::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiInPort_visual::toggleTrace -- switches the state of trace +// Returns the previous value of the trace variable. +// + +void MidiInPort_visual::toggleTrace(void) { + trace = !trace; +} + + + +////////////////////////////// +// +// MidiInPort_visual::unpause -- enables the Midi input port +// to inserting MIDI messages into the buffer after the +// port is already open. +// + +void MidiInPort_visual::unpause(void) { + if (getPort() == -1) { + return; + } + + if (openQ[getPort()]) { + if (inrunningQ[getPort()] == 0) { + midiInStart(device[getPort()]); + inrunningQ[getPort()] = 1; + } + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiInPort_visual::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiInPort_visual::deinitialize(void) { + int num = numDevices; + + closeAll(); + + if (sysexBuffers != NULL) { + for (int i=0; i[numDevices]; + + // allocate space for the MIDI sysex buffer indices + if (sysexWriteBuffer != NULL) delete [] sysexWriteBuffer; + sysexWriteBuffer = new int[numDevices]; + + // allocate space for the sysex MIM_LONGDATA message tracking + if (sysexStatus != NULL) delete [] sysexStatus; + sysexStatus = new int[numDevices]; + + // allocate space for sysex buffers + if (sysexBuffers != NULL) { + cout << "Error: memory leak on sysex buffers initialization" << endl; + exit(1); + } + sysexBuffers = new Array*[numDevices]; + + // allocate system exclusive buffers for MIDI driver + if (sysexDriverBuffer1 != NULL) { + cout << "Error: memory leak on sysex buffer for drivers creation" << endl; + exit(1); + } + sysexDriverBuffer1 = new MIDIHDR*[numDevices]; + for (i=0; i[128]; + for (int n=0; n<128; n++) { + sysexBuffers[i][n].allowGrowth(0); // shouldn't need to grow + sysexBuffers[i][n].setAllocSize(32); + sysexBuffers[i][n].setSize(0); + sysexBuffers[i][n].setGrowth(32); // in case it will ever grow + } + + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::installSysexStuff -- install all the mess that +// a MIDIIN structure needs in order to receive system exclusives. +// + +void MidiInPort_visual::installSysexStuff(HMIDIIN dev, int port) { + if (sysexDriverBuffer1 != NULL) { + if (sysexDriverBuffer1[port] != NULL) { + // some memory leaks here + delete sysexDriverBuffer1[port]; + sysexDriverBuffer1[port] = NULL; + } + } + if (sysexDriverBuffer2 != NULL) { + if (sysexDriverBuffer2[port] != NULL) { + // some memory leaks here + delete sysexDriverBuffer2[port]; + sysexDriverBuffer2[port] = NULL; + } + } + + // allocate space for Drivers sysex byte buffer + sysexDriverBuffer1[port] = (LPMIDIHDR)GlobalLock(GlobalAlloc(GMEM_MOVEABLE | + GMEM_SHARE, sizeof(MIDIHDR))); + sysexDriverBuffer2[port] = (LPMIDIHDR)GlobalLock(GlobalAlloc(GMEM_MOVEABLE | + GMEM_SHARE, sizeof(MIDIHDR))); + + if (sysexDriverBuffer1[port] == NULL) { + cout << "Error: could not allocate sysex driver's buffer" << endl; + exit(1); + } + + if (sysexDriverBuffer2[port] == NULL) { + cout << "Error: could not allocate sysex driver's buffer" << endl; + exit(1); + } + + // allocate buffer inside of sysexDriverBuffer + sysexDriverBuffer1[port]->lpData = (LPSTR)GlobalLock(GlobalAlloc( + GMEM_MOVEABLE | GMEM_SHARE, (DWORD)1024)); + sysexDriverBuffer2[port]->lpData = (LPSTR)GlobalLock(GlobalAlloc( + GMEM_MOVEABLE | GMEM_SHARE, (DWORD)1024)); + + if (sysexDriverBuffer1[port]->lpData == NULL) { + cout << "Error: there was not enought space to allocate sysex buffer" + << endl; + // leaking memory here + exit(1); + } + + if (sysexDriverBuffer2[port]->lpData == NULL) { + cout << "Error: there was not enought space to allocate sysex buffer" + << endl; + // leaking memory here + exit(1); + } + + + // setup other sysexDriverBuffer data fields + sysexDriverBuffer1[port]->dwBufferLength = 1024; // total size of buffer + sysexDriverBuffer1[port]->dwBytesRecorded = 0L; // number of byte in buffer + sysexDriverBuffer1[port]->dwFlags = 0L; // initialize flags + sysexDriverBuffer1[port]->dwUser = 0L; // userdata: used for sysex time + + // setup other sysexDriverBuffer data fields + sysexDriverBuffer2[port]->dwBufferLength = 1024; // total size of buffer + sysexDriverBuffer2[port]->dwBytesRecorded = 0L; // number of byte in buffer + sysexDriverBuffer2[port]->dwFlags = 0L; // initialize flags + sysexDriverBuffer2[port]->dwUser = 0L; // userdata: used for sysex time + + // prepare the header + int status = midiInPrepareHeader(device[port], sysexDriverBuffer1[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error preparing sysex buffer number: " << port << endl; + // leaking some memory here? + exit(1); + } + + // prepare the header + status = midiInPrepareHeader(device[port], sysexDriverBuffer2[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error preparing sysex buffer number: " << port << endl; + // leaking some memory here? + exit(1); + } + + // add the sysex buffer to the driver + status = midiInAddBuffer(device[port], sysexDriverBuffer1[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error adding sysex buffer to driver: " << port << endl; + // leaking some memory here? + exit(1); + } + + status = midiInAddBuffer(device[port], sysexDriverBuffer2[port], + sizeof(MIDIHDR)); + + if (status != 0) { + cout << "Error adding sysex buffer to driver: " << port << endl; + // leaking some memory here? + exit(1); + } + +} + + + +////////////////////////////// +// +// MidiInPort_visual::uninstallSysexStuff -- uninstalls all the mess that +// a MIDIIN structure needs in order to receive system exclusives. +// + +void MidiInPort_visual::uninstallSysexStuff(HMIDIIN dev, int port) { + if (port == -1) { + return; + } + // unprepare the headers + midiInUnprepareHeader(device[port], sysexDriverBuffer1[port], + sizeof(MIDIHDR)); + midiInUnprepareHeader(device[port], sysexDriverBuffer2[port], + sizeof(MIDIHDR)); + + // deallocate buffer inside of sysexDriverBuffer + /* Following code caused problems: perhaps lpData was deleted by driver + delete [] sysexDriverBuffer1[port]->lpData; + sysexDriverBuffer1[port]->lpData = NULL; + delete [] sysexDriverBuffer2[port]->lpData; + sysexDriverBuffer2[port]->lpData = NULL; + */ + + // deallocate space for Drivers sysex byte buffer + delete sysexDriverBuffer1[port]; + delete sysexDriverBuffer2[port]; + sysexDriverBuffer1[port] = NULL; + sysexDriverBuffer2[port] = NULL; +} + + + +////////////////////////////// +// +// MidiInPort_visual::releaseMutex +// + +void MidiInPort_visual::releaseMutex(void) { +/* int flag = */ ReleaseMutex(hMutex[getPort()]); +/* + if (flag != 0) { + cerr << "Error relasing mutex in MIDI input; flag was: " << flag << endl; + } +*/ +} + + + +////////////////////////////// +// +// MidiInPort_visual::setPortStatus +// + +void MidiInPort_visual::setPortStatus(int aStatus) { + if (getPort() == -1) { + return; + } + + if (aStatus) { + openQ[getPort()] = 1; + } else { + openQ[getPort()] = 0; + } +} + + + +////////////////////////////// +// +// MidiInPort_visual::waitForMutex +// + +void MidiInPort_visual::waitForMutex(void) { +/* + DWORD mutexResult = WaitForSingleObject(hMutex[getPort()], 5000L); + if (mutexResult != WAIT_OBJECT_0) { + cerr << "Error waiting for mutex in MIDI input" << endl; + } +*/ +} + + + +/////////////////////////////////////////////////////////////////////////// + + +////////////////////////////// +// +// midiInputCallback -- the function the MIDI input driver calls when +// it has a message from the Midi in cable ready +// + +void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT inputStatus, + DWORD instancePtr, DWORD midiMessage, DWORD timestamp) { + static MidiMessage newMessage; + + switch (inputStatus) { + case MIM_MOREDATA: + // There is more data waiting at the device. + // If this case is exists, then that means that the MIDI + // device is too slow and some data was lost. + // Windows sends a MIM_MOREDATA event only if you specify + // the MIDI_IO_STATUS flag to midiInOpen(). + + // no break; + case MIM_DATA: + + // One regular (non sysex) message has been completely + // received. + + // ignore the Yamaha Active Sensing command and MIDI time clock + // at least for now. + if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) { + break; + } + + newMessage.time = timestamp; + newMessage.data = midiMessage; + ((MidiInPort_visual*)instancePtr)->insert(newMessage); + if (((MidiInPort_visual*)instancePtr)->getTrace()) { + cout << "[" << hex << (int)newMessage.command() << dec + << ":" << (int)newMessage.p1() << "," + << (int)newMessage.p2() << "]"; + cout.flush(); + } + break; + + case MIM_LONGDATA: + { + // A sysex or part of a sysex message is coming in. + // The timestamp variable contains a pointer to a + // MIDIHDR pointer + + MIDIHDR* midiheader = (MIDIHDR*)midiMessage; + int dataCount = midiheader->dwBytesRecorded; + char* data = midiheader->lpData; + int port = ((MidiInPort_visual*)instancePtr)->getPort(); + if (port == -1) { + break; + } + int* sysexStatus = ((MidiInPort_visual*)instancePtr)->sysexStatus; +// MIDIHDR** sysexDriverBuffer = ((MidiInPort_visual*)instancePtr)-> +// sysexDriverBuffer; + HMIDIIN devicex = ((MidiInPort_visual*)instancePtr)->device[port]; + + if (dataCount == 0) { + // can't handle a zero-length sysex + break; + } + + // step 1: determine if this is the first part of the sysex + // message or a continuation + int continuation = 0; + if (data[0] == (char)0xf0) { + continuation = 0; + if (sysexStatus[port] != -1) { + cout << "Error: there is another sysex command being " + "received on port " << port << endl; + exit(1); + } + } else { + if (sysexStatus[port] == -1) { + cout << "Error: no sysex command is being " + "received on port " << port << endl; + if (data[0] < 128) { + cout << "First byte is: " << dec << (int)data[0] << endl; + } else { + cout << "First byte is: " << hex << (int)data[0] << endl; + } + if (data[1] < 128) { + cout << "Second byte is: " << dec << (int)data[1] << endl; + } else { + cout << "Second byte is: " << hex << (int)data[1] << endl; + } + + exit(1); + } + continuation = 1; + } + + // step 2: if continuing, add the data to the preallocated + // sysex buffer, otherwise, get a new buffer location + int buffer = -1; + if (continuation) { + buffer = sysexStatus[port]; + if (buffer < 0 || buffer > 127) { + cout << "Sysex buffer was out of range: " << buffer << endl; + } + for (int i=0; i + sysexBuffers[port][buffer].append(datum); + if (datum == 0xf7) { + for (int k=i; kdwBytesRecorded = dataCount - i - 1; + + goto insert_sysex_message; + } + } + } else { // if not a continuation of a sysex event + buffer = ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port]; + ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port]++; + if (buffer == 127) { + ((MidiInPort_visual*)instancePtr)->sysexWriteBuffer[port] = 0; + } + + ((MidiInPort_visual*)instancePtr)-> + sysexBuffers[port][buffer].setSize(0); + for (int j=0; j + sysexBuffers[port][buffer].append(datum); + if (datum == 0xf7) { + for (int k=j; kinsert(newMessage); + if (((MidiInPort_visual*)instancePtr)->getTrace()) { + cout << "[" << hex << (int)newMessage.command() << dec + << ":" << (int)newMessage.p1() << "," + << (int)newMessage.p2() << "]"; + cout.flush(); + } + + } // end of local variable range + break; + + case MIM_ERROR: + // An invalid regular MIDI message was received. + + break; + + case MIM_LONGERROR: + { + // An invalid sysex MIDI message was received. + + // if a sysex message was continuing from a previous part, + // then kill that message. + + int port = ((MidiInPort_visual*)instancePtr)->getPort(); + if (port == -1) { + break; + } + int buffer = ((MidiInPort_visual*)instancePtr)->sysexStatus[port]; + if (buffer != -1) { + ((MidiInPort_visual*)instancePtr)-> + sysexBuffers[port][buffer].setSize(0); + ((MidiInPort_visual*)instancePtr)->sysexStatus[port] = -1; + } + + HMIDIIN devicex = ((MidiInPort_visual*)instancePtr)->device[port]; + MIDIHDR* midiheader = (MIDIHDR*)midiMessage; + + // recycle the MIDI input buffer for the driver + midiInPrepareHeader(devicex, midiheader, sizeof(MIDIHDR)); + int status = midiInAddBuffer(devicex, midiheader, sizeof(MIDIHDR)); + if (status != MMSYSERR_NOERROR) { + cout << "Error when calling midiInAddBuffer" << endl; + exit(1); + } + + + break; + } + default: ; + // case MIM_OPEN: // MIDI device is opening + // case MIM_CLOSE: // MIDI device is closing + } +} + + + +#endif // VISUAL + + +// md5sum: db55d9f375b86f54c0c8340547c5701f - MidiInPort_visual.cpp =css= 20030102 diff --git a/src/midiio/src/MidiInput.cpp b/src/midiio/src/MidiInput.cpp new file mode 100644 index 0000000..93fce87 --- /dev/null +++ b/src/midiio/src/MidiInput.cpp @@ -0,0 +1,224 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: 18 December 1997 +// Last Modified: Sun Jan 25 15:31:49 GMT-0800 1998 +// Last Modified: Thu Apr 27 17:56:03 PDT 2000 (added scale function) +// Filename: ...sig/code/control/MidiInput/MidiInput.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiInput.cpp +// Syntax: C++ +// +// Description: A higher-level MIDI input interface than the +// MidiInPort class. Can be used to allow multiple +// objects to share a single MIDI input stream, or +// to fake a MIDI input connection. +// + +#include "MidiInput.h" +#include +#include + + +////////////////////////////// +// +// MidiInput::MidiInput -- opens the specified MIDI input device and +// sets the size of the input buffer. +// + +MidiInput::MidiInput(void) : MidiInPort() { + orphanBuffer = NULL; +} + + +MidiInput::MidiInput(int aPort, int autoOpen) : MidiInPort(aPort, autoOpen) { + orphanBuffer = NULL; +} + + + +////////////////////////////// +// +// MidiInput::~MidiInput +// + +MidiInput::~MidiInput() { + if (orphanBuffer != NULL) { + delete orphanBuffer; + orphanBuffer = NULL; + } +} + + + +////////////////////////////// +// +// MidiInput::getBufferSize +// + +int MidiInput::getBufferSize(void) { + if (isOrphan()) { + return orphanBuffer->getSize(); + } else { + return MidiInPort::getBufferSize(); + } +} + + + +////////////////////////////// +// +// MidiInput::getCount +// + +int MidiInput::getCount(void) { + if (isOrphan()) { + return orphanBuffer->getCount(); + } else { + return MidiInPort::getCount(); + } +} + + + +////////////////////////////// +// +// MidiInput::extract +// + +MidiMessage MidiInput::extract(void) { + if (isOrphan()) { + return orphanBuffer->extract(); + } else { + return MidiInPort::extract(); + } +} + + + +////////////////////////////// +// +// fscale -- converts a value in the range from 0 to 127 +// into a number in a new range. For example the value +// 64 scaled to the range from 0 to 2 would be 1. +// + +double MidiInput::fscale(int value, double min, double max) { + return value >= 127 ? max : (value/127.0*(max-min)+min); +} + + + +////////////////////////////// +// +// fscale14 -- converts a value in the range from 0 to 2^15-1 +// into a number in a new range. +// + +double MidiInput::fscale14(int value, double min, double max) { + return value >= 16383 ? max : (value/16383.0*(max-min)+min); +} + + + +////////////////////////////// +// +// MidiInput::insert +// + +void MidiInput::insert(const MidiMessage& aMessage) { + if (isOrphan()) { + orphanBuffer->insert(aMessage); + } else { + MidiInPort::insert(aMessage); + } +} + + + +////////////////////////////// +// +// MidiInput::isOrphan +// + +int MidiInput::isOrphan(void) const { + if (orphanBuffer == NULL) { + return 0; + } else { + return 1; + } +} + + + +////////////////////////////// +// +// MidiInput::makeOrphanBuffer +// default value: aSize = 1024 +// + +void MidiInput::makeOrphanBuffer(int aSize) { + if (!isOrphan()) { + if (orphanBuffer == NULL) { + delete orphanBuffer; + orphanBuffer = NULL; + } + orphanBuffer = new CircularBuffer(aSize); + } +} + + + +////////////////////////////// +// +// MidiInput::removeOrphanBuffer +// + +void MidiInput::removeOrphanBuffer(void) { + if (isOrphan()) { + delete orphanBuffer; + orphanBuffer = NULL; + } +} + + + +////////////////////////////// +// +// scale -- converts a value in the range from 0 to 127 +// into a number in a new range. For example the value +// 64 scaled to the range from 0 to 2 would be 1. +// + +int MidiInput::scale(int value, int min, int max) { + return value >= 127 ? max : (int)(value/127.0*(max-min+1)+min); +} + + + +////////////////////////////// +// +// scale14 -- converts a value in the range from 0 to 2^15-1 +// into a number in a new range. +// + +int MidiInput::scale14(int value, int min, int max) { + return value >= 16383 ? max : (int)(value/16383.0*(max-min+1)+min); +} + + + +////////////////////////////// +// +// MidiInput::setBufferSize +// + +void MidiInput::setBufferSize(int aSize) { + if (isOrphan()) { + orphanBuffer->setSize(aSize); + } else { + MidiInPort::setBufferSize(aSize); + } +} + + + +// md5sum: 826d403708263eaf0089b4742179c58c - MidiInput.cpp =css= 20030102 diff --git a/src/midiio/src/MidiMessage.cpp b/src/midiio/src/MidiMessage.cpp new file mode 100644 index 0000000..5f3df19 --- /dev/null +++ b/src/midiio/src/MidiMessage.cpp @@ -0,0 +1,406 @@ +// +// Copyright 1997-1998 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: 19 December 1997 +// Last Modified: Fri Jan 23 00:26:12 GMT-0800 1998 +// Last Modified: Sun Sep 20 12:17:26 PDT 1998 +// Last Modified: Mon Oct 15 14:29:12 PDT 2001 (added is_note functions) +// Filename: ...sig/src/sigControl/MidiMessage.cpp +// Web Address: http://sig.sapp.org/src/sigControl/MidiMessage.cpp +// Syntax: C++ +// +// Description: A structure for handling MIDI input messages. +// This class stores a time stamp plus up to +// four MIDI message bytes. System Exclusive messages +// are stored in a separate array in the MidiInPort +// class, and their storage index is passed to the +// user through a MIDI message for later extraction +// of the full sysex message. +// + +#include "MidiMessage.h" + + +////////////////////////////// +// +// MidiMessage::MidiMessage +// + +MidiMessage::MidiMessage(void) { + // no initialization. Note that the default contents are undefined. +} + + +// default value aTime = 0 +MidiMessage::MidiMessage(int aCommand, int aP1, int aP2, int aTime) { + time = aTime; + command() = (uchar)aCommand; + p1() = (uchar)aP1; + p2() = (uchar)aP2; +} + + +MidiMessage::MidiMessage(const MidiMessage& aMessage) { + time = aMessage.time; + data = aMessage.data; +} + + + +////////////////////////////// +// +// MidiMessage::~MidiMessage -- Destructor. +// + +MidiMessage::~MidiMessage() { + // do nothing +} + + + +////////////////////////////// +// +// MidiMessage::command -- returns the MIDI command byte +// + +uchar& MidiMessage::command(void) { + return p0(); +} + + + +////////////////////////////// +// +// MidiMessage::operator= -- defines how objects are to be copied +// + +MidiMessage& MidiMessage::operator=(const MidiMessage& aMessage) { + time = aMessage.time; + data = aMessage.data; + return *this; +} + + + +////////////////////////////// +// +// MidiMessage::operator[] -- access to byte data +// can only access index 0 to 3, other number will be +// chopped. +// + +uchar& MidiMessage::operator[](int index) { + return *(((uchar*)&data)+(index & 0x3)); +} + + + +////////////////////////////// +// +// MidiMessage::p0 -- returns the command byte of the +// midi message. Same as the command() function. +// + +uchar& MidiMessage::p0(void) { + return *(((uchar*)&data)+0); +} + + + +////////////////////////////// +// +// MidiMessage::p1 -- returns the first parameter of the +// midi message. Valid if the command requires a parameter. +// + +uchar& MidiMessage::p1(void) { + return *(((uchar*)&data)+1); +} + + + +////////////////////////////// +// +// MidiMessage::p2 -- returns the second parameter of the +// midi message. Valid if the command requires two parameters. +// + +uchar& MidiMessage::p2(void) { + return *(((uchar*)&data)+2); +} + + +////////////////////////////// +// +// MidiMessage::p3 -- returns the third parameter of the +// midi message. Valid if the command requires three parameters +// (but none of the MIDI command do). +// + +uchar& MidiMessage::p3(void) { + return *(((uchar*)&data)+3); +} + + + +////////////////////////////// +// +// MidiMessage:getArgCount -- +// + +int MidiMessage::getArgCount(void) const { + return getParameterCount(); +} + + + +////////////////////////////// +// +// MidiMessage::getParameterCount -- returns the number +// of valid parameters for the assiciated MIDI command +// stored in p0. Returns -1 if MIDI command is invalid, +// or the number of valid parameters is unknown. +// + +int MidiMessage::getParameterCount(void) const { + int output = -1; + switch (*(((uchar*)&data)+0) & 0xf0) { + case 0x80: // note-off + case 0x90: // note-on + case 0xa0: // aftertouch + case 0xb0: // continuous controller + case 0xe0: // pitch wheel + output = 2; + break; + case 0xc0: // patch change + case 0xd0: // channel pressure + output = 1; + break; + case 0xf0: + switch (*(((uchar*)&data)+0)) { + // System Common Messages + case 0xf0: return -1; // variable for sysex + case 0xf1: return 1; // MIDI Time Code Quarter Frame + case 0xf2: return 2; // Song Position Pointer + case 0xf3: return 1; // Song Select + case 0xf4: return 0; // Undefined + case 0xf5: return 0; // Undefined + case 0xf6: return 0; // Tune Request + case 0xf7: return 0; // End of System exclusive + // System Real-Time Messages + case 0xf8: return 0; // Timing Clock + case 0xf9: return 0; // Undefined + case 0xfa: return 0; // Start + case 0xfb: return 0; // Continue + case 0xfc: return 0; // Stop + case 0xfd: return 0; // Undefined + case 0xfe: return 0; // Active Sensing + case 0xff: return 0; // System Reset + } + return -1; + break; + default: // don't know or invalid command + output = -1; + break; + } + + return output; +} + + + +////////////////////////////// +// +// MidiMessage::getCommand -- same as command(). +// + +uchar MidiMessage::getCommand(void) const { + return getP0(); +} + + + +////////////////////////////// +// +// MidiMessage::getP0 -- same as p0(). +// + +uchar MidiMessage::getP0(void) const { + return *(((uchar*)&data)+0); +} + + + +////////////////////////////// +// +// MidiMessage::getP1 -- same as p1(). +// + +uchar MidiMessage::getP1(void) const { + return *(((uchar*)&data)+1); +} + + + +////////////////////////////// +// +// MidiMessage::getP2 -- same as p2(). +// + +uchar MidiMessage::getP2(void) const { + return *(((uchar*)&data)+2); +} + + + +////////////////////////////// +// +// MidiMessage::getP3 -- same as p3(). +// + +uchar MidiMessage::getP3(void) const { + return *(((uchar*)&data)+3); +} + + + +////////////////////////////// +// +// MidiMessage::setCommand -- same as command(). +// + +void MidiMessage::setCommand(uchar aCommand) { + command() = aCommand; +} + + + +////////////////////////////// +// +// MidiMessage::setData -- sets the message bytes +// default values: aP1 = 0, aP2 = 0, aP3 = 0. +// + +void MidiMessage::setData(uchar aCommand, uchar aP1, uchar aP2, uchar aP3) { + setCommand(aCommand); + setP1(aP1); + setP2(aP2); + setP3(aP3); +} + + + +////////////////////////////// +// +// MidiMessage::setP0 -- same as p0(). +// + +void MidiMessage::setP0(uchar aP0) { + p0() = aP0; +} + + + +////////////////////////////// +// +// MidiMessage::setP1 -- same as p1(). +// + +void MidiMessage::setP1(uchar aP1) { + p1() = aP1; +} + + + +////////////////////////////// +// +// MidiMessage::setP2 -- same as p2(). +// + +void MidiMessage::setP2(uchar aP2) { + p2() = aP2; +} + + + +////////////////////////////// +// +// MidiMessage::setP3 -- same as p3(). +// + +void MidiMessage::setP3(uchar aP3) { + p3() = aP3; +} + + + +////////////////////////////// +// +// MidiMessage::is_note -- Returns true if the MIDI command is 0x80 or 0x90. +// + +int MidiMessage::is_note(void) { + if ((p0() & 0xf0) == 0x90) { // note-on or note-off + return 1; + } else if ((p0() & 0xf0) == 0x80) { // note-off + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiMessage::is_note_on -- Returns true if the MIDI command is a note +// on message (0x90 series with p2() > 0). +// + +int MidiMessage::is_note_on(void) { + if (((p0() & 0xf0) == 0x90) && p2() > 0) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiMessage::is_note_off -- Returns true if the MIDI command is a note +// off message (0x80 series or 0x90 series with p2() == 0). +// + +int MidiMessage::is_note_off(void) { + if ((p0() & 0xf0) == 0x80) { + return 1; + } else if (((p0() & 0xf0) == 0x90) && (p2() == 0)) { + return 1; + } else { + return 0; + } +} + + +/////////////////////////////////////////////////////////////////////////// + +////////////////////////////// +// +// operator<< MidiMessage +// + +std::ostream& operator<<(std::ostream& out, MidiMessage& aMessage) { + out << "(" << aMessage.time << ") " + << std::hex << (int)aMessage.getP0() << ": "; + for (int i=1; i<=aMessage.getArgCount(); i++) { + out << std::dec << (int)aMessage[i] << ' '; + } + + return out; +} + + + +// md5sum: 487f0fddeb8db20d81f9c039e2a460c9 - MidiMessage.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_alsa.cpp b/src/midiio/src/MidiOutPort_alsa.cpp new file mode 100644 index 0000000..07f4e5d --- /dev/null +++ b/src/midiio/src/MidiOutPort_alsa.cpp @@ -0,0 +1,469 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Wed May 10 16:16:21 PDT 2000 +// Last Modified: Sun May 14 20:44:12 PDT 2000 +// Filename: ...sig/code/control/MidiOutPort/alsa/MidiOutPort_alsa.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiOutPort_alsa.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// ALSA sound drivers. Privately inherited by the +// MidiOutPort class via the MidiOutPort_alsa class. +// + +#if defined(LINUX) && defined(ALSA) + +#include "MidiOutPort_alsa.h" +#include +#include + +// initialized static variables +int MidiOutPort_alsa::numDevices = 0; +int MidiOutPort_alsa::objectCount = 0; +int* MidiOutPort_alsa::portObjectCount = NULL; +int MidiOutPort_alsa::channelOffset = 0; +int* MidiOutPort_alsa::trace = NULL; +std::ostream* MidiOutPort_alsa::tracedisplay = &std::cout; + + + +////////////////////////////// +// +// MidiOutPort_alsa::MidiOutPort_alsa +// default values: autoOpen = 1 +// + +#include + +MidiOutPort_alsa::MidiOutPort_alsa(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_alsa::MidiOutPort_alsa(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::~MidiOutPort_alsa -- +// + +MidiOutPort_alsa::~MidiOutPort_alsa() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cout << "Error: bad MidiOutPort object count!: " << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::close -- +// + +void MidiOutPort_alsa::close(void) { + Sequencer_alsa::closeOutput(getPort()); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::closeAll -- +// + +void MidiOutPort_alsa::closeAll(void) { + int i; + for (i=0; i= getNumPorts()) { + std::cout << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_alsa::setTrace(int aState) { + if (getPort() == -1) return -1; + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::sysex -- send a system exclusive message. +// The message must start with a 0xf0 byte and end with +// a 0xf7 byte. +// + +int MidiOutPort_alsa::sysex(uchar* array, int size) { + if (getPort() == -1) { + return 2; + } + + if (size == 0 || array[0] != 0xf0 || array[size-1] != 0xf7) { + std::cout << "Error: invalid sysex message" << std::endl; + exit(1); + } + + return rawsend(array,size); +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::toggleTrace -- +// + +void MidiOutPort_alsa::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_alsa::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_alsa::deinitialize(void) { + closeAll(); + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; + if (trace != NULL) delete [] trace; + trace = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_alsa::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_alsa::initialize(void) { + // get the number of ports + numDevices = getNumOutputs(); + if (getNumPorts() <= 0) { + std::cout << "Warning: no MIDI output devices" << std::endl; + portObjectCount = NULL; + trace = NULL; + } else { + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for trace variable for each port: + if (trace != NULL) delete [] trace; + trace = new int[numDevices]; + + // initialize the static arrays + for (int i=0; i +// Creation Date: Sun May 14 20:58:32 PDT 2000 +// Last Modified: Thu May 18 23:37:11 PDT 2000 +// Last Modified: Sat Nov 2 20:40:01 PST 2002 (added ALSA OSS def) +// Filename: ...sig/code/control/MidiOutPort_linux/MidiOutPort_linux.cpp +// Web Address: http://sig.sapp.org/include/sig/MidiOutPort_linux.cpp +// Syntax: C++ +// +// Description: Linux MIDI output class which detects which +// type of MIDI drivers are available: either +// ALSA or OSS. +// + +#ifdef LINUX +#if defined(ALSA) && defined(OSS) + +#include "MidiOutPort_linux.h" +#include +#include +#include + + +// initialize static members +int MidiOutPort_linux::objectCount = 0; +int MidiOutPort_linux::current = UNKNOWN_MIDI_SELECT; // MIDI out selected +int MidiOutPort_linux::alsaQ = 0; // boolean for if ALSA is present +int MidiOutPort_linux::ossQ = 0; // boolean for if OSS is present + +MidiOutPort_oss *MidiOutPort_linux::oss_output = NULL; +MidiOutPort_alsa *MidiOutPort_linux::alsa_output = NULL; +MidiOutPort_unsupported *MidiOutPort_linux::unknown_output = NULL; + + +MidiOutPort_linux::MidiOutPort_linux(void) { + if (objectCount == 0) { + determineDrivers(); + } else if (objectCount < 0) { + cout << "Error: unusual MidiOutPort_linux object count" << endl; + exit(1); + } + + objectCount++; +} + +MidiOutPort_linux::MidiOutPort_linux(int aPort, int autoOpen = 1) { + determineDrivers(); + setAndOpenPort(aPort); +} + +MidiOutPort_linux::~MidiOutPort_linux() { + objectCount--; + if (objectCount == 0) { + if (oss_output != NULL) { + delete oss_output; + oss_output = NULL; + } + + if (alsa_output != NULL) { + delete alsa_output; + alsa_output = NULL; + } + + if (unknown_output != NULL) { + delete unknown_output; + unknown_output = NULL; + } + } + + if (objectCount < 0) { + cout << "Error: unusual MidiOutPort_linux count when destructing" << endl; + exit(1); + } +} + + +void MidiOutPort_linux::close(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->close(); break; + case ALSA_MIDI_SELECT: alsa_output->close(); break; + default: unknown_output->close(); break; + } +} + +void MidiOutPort_linux::closeAll(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->closeAll(); break; + case ALSA_MIDI_SELECT: alsa_output->closeAll(); break; + default: unknown_output->closeAll(); break; + } +} + +int MidiOutPort_linux::getChannelOffset(void) const { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getChannelOffset(); break; + case ALSA_MIDI_SELECT: return alsa_output->getChannelOffset(); break; + default: return unknown_output->getChannelOffset(); break; + } +} + +const char* MidiOutPort_linux::getName(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getName(); break; + case ALSA_MIDI_SELECT: return alsa_output->getName(); break; + default: return unknown_output->getName(); break; + } +} + +const char* MidiOutPort_linux::getName(int i) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getName(i); break; + case ALSA_MIDI_SELECT: return alsa_output->getName(i); break; + default: return unknown_output->getName(i); break; + } +} + +int MidiOutPort_linux::getNumPorts(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getNumPorts(); break; + case ALSA_MIDI_SELECT: return alsa_output->getNumPorts(); break; + default: return unknown_output->getNumPorts(); break; + } +} + +int MidiOutPort_linux::getPort(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getPort(); break; + case ALSA_MIDI_SELECT: return alsa_output->getPort(); break; + default: return unknown_output->getPort(); break; + } +} + +int MidiOutPort_linux::getPortStatus(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getPortStatus(); break; + case ALSA_MIDI_SELECT: return alsa_output->getPortStatus(); break; + default: return unknown_output->getPortStatus(); break; + } +} + +int MidiOutPort_linux::getTrace(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->getTrace(); break; + case ALSA_MIDI_SELECT: return alsa_output->getTrace(); break; + default: return unknown_output->getTrace(); break; + } +} + +int MidiOutPort_linux::open(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->open(); break; + case ALSA_MIDI_SELECT: return alsa_output->open(); break; + default: return unknown_output->open(); break; + } +} + +int MidiOutPort_linux::rawsend(int command, int p1, int p2) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(command, p1, p2); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(command, p1, p2); break; + default: return unknown_output->rawsend(command, p1, p2); break; + } +} + +int MidiOutPort_linux::rawsend(int command, int p1) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(command, p1); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(command, p1); break; + default: return unknown_output->rawsend(command, p1); break; + } +} + +int MidiOutPort_linux::rawsend(int command) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(command); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(command); break; + default: return unknown_output->rawsend(command); break; + } +} + +int MidiOutPort_linux::rawsend(uchar* array, int size) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->rawsend(array, size); break; + case ALSA_MIDI_SELECT: return alsa_output->rawsend(array, size); break; + default: return unknown_output->rawsend(array, size); break; + } +} + +void MidiOutPort_linux::setAndOpenPort(int aPort) { + switch (getSelect()) { + case OSS_MIDI_SELECT: + oss_output->setPort(aPort); + oss_output->open(); + break; + case ALSA_MIDI_SELECT: + alsa_output->setPort(aPort); + alsa_output->open(); + break; + default: + unknown_output->setPort(aPort); + unknown_output->open(); + break; + } +} + +void MidiOutPort_linux::setChannelOffset(int aChannel) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->setChannelOffset(aChannel); break; + case ALSA_MIDI_SELECT: alsa_output->setChannelOffset(aChannel); break; + default: unknown_output->setChannelOffset(aChannel); break; + } +} + +void MidiOutPort_linux::setPort(int aPort) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->setPort(aPort); break; + case ALSA_MIDI_SELECT: + alsa_output->setPort(aPort); break; + default: unknown_output->setPort(aPort); break; + } +} + +int MidiOutPort_linux::setTrace(int aState) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->setTrace(aState); break; + case ALSA_MIDI_SELECT: return alsa_output->setTrace(aState); break; + default: return unknown_output->setTrace(aState); break; + } +} + +int MidiOutPort_linux::sysex(uchar* array, int size) { + switch (getSelect()) { + case OSS_MIDI_SELECT: return oss_output->sysex(array, size); break; + case ALSA_MIDI_SELECT: return alsa_output->sysex(array, size); break; + default: return unknown_output->sysex(array, size); break; + } +} + +void MidiOutPort_linux::toggleTrace(void) { + switch (getSelect()) { + case OSS_MIDI_SELECT: oss_output->toggleTrace(); break; + case ALSA_MIDI_SELECT: alsa_output->toggleTrace(); break; + default: unknown_output->toggleTrace(); break; + } +} + + + +////////////////////////////// +// +// MidiOutPort_linux::getSelect -- return the type of MIDI which +// is being used to send MIDI output. +// + +int MidiOutPort_linux::getSelect(void) { + return current; +} + + + +////////////////////////////// +// +// MidiOutPort_linux::selectOSS -- select the OSS MIDI output +// returns 1 if OSS is available, otherwise returns 0. +// + +int MidiOutPort_linux::selectOSS(void) { + if (ossQ) { + current = OSS_MIDI_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_linux::selectALSA -- select the ALSA MIDI output +// returns 1 if ALSA is available, otherwise returns 0. +// + +int MidiOutPort_linux::selectALSA(void) { + if (alsaQ) { + current = ALSA_MIDI_SELECT; + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// MidiOutPort_linux::selectUnknown -- select the Unknown MIDI output +// returns 1 always. +// + +int MidiOutPort_linux::selectUnknown(void) { + current = UNKNOWN_MIDI_SELECT; + return 1; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private Functions +// + +#include + +////////////////////////////// +// +// MidiOutPort_linux::determineDrivers -- see if OSS/ALSA are +// available. If /dev/sequencer is present, assume that OSS is +// available. If /dev/snd/sdq is present, assume that ALSA is +// available. +// + +void MidiOutPort_linux::determineDrivers(void) { + struct stat filestats; + int status; + status = stat("/dev/sequencer", &filestats); + + if (status != 0) { + ossQ = 0; + } else { + ossQ = 1; + } + + status = stat("/dev/snd/seq", &filestats); + + if (status != 0) { + alsaQ = 0; + } else { + alsaQ = 1; + } + + + current = UNKNOWN_MIDI_SELECT; + + if (ossQ) { + current = OSS_MIDI_SELECT; + } + + if (alsaQ) { + current = ALSA_MIDI_SELECT; + } + + // create MIDI output types which are available: + + if (oss_output != NULL) { + delete oss_output; + oss_output = NULL; + } + if (alsa_output != NULL) { + delete alsa_output; + alsa_output = NULL; + } + if (unknown_output != NULL) { + delete unknown_output; + unknown_output = NULL; + } + + if (ossQ) { + oss_output = new MidiOutPort_oss; + } + if (alsaQ) { + alsa_output = new MidiOutPort_alsa; + } + unknown_output = new MidiOutPort_unsupported; +} + + +#endif /* ALSA and OSS */ +#endif /* LINUX */ + +// md5sum: be1ccf667122f1c9cf56a95b2ffb8e79 - MidiOutPort_linux.cpp =css= 20030102 diff --git a/src/midiio/src/MidiOutPort_oss.cpp b/src/midiio/src/MidiOutPort_oss.cpp new file mode 100644 index 0000000..74f17c4 --- /dev/null +++ b/src/midiio/src/MidiOutPort_oss.cpp @@ -0,0 +1,462 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Fri Dec 18 19:22:20 PST 1998 +// Last Modified: Fri Jan 8 04:26:16 PST 1999 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/code/control/MidiOutPort/linux/MidiOutPort_oss.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiOutPort_oss.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Linux using +// OSS sound drivers. Privately inherited by the +// MidiOutPort class. +// + +#ifdef LINUX + +#include "MidiOutPort_oss.h" +#include +#include + +// initialized static variables +int MidiOutPort_oss::numDevices = 0; +int MidiOutPort_oss::objectCount = 0; +int* MidiOutPort_oss::portObjectCount = NULL; +int MidiOutPort_oss::channelOffset = 0; +int* MidiOutPort_oss::trace = NULL; +std::ostream* MidiOutPort_oss::tracedisplay = &std::cout; + + + +////////////////////////////// +// +// MidiOutPort_oss::MidiOutPort_oss +// default values: autoOpen = 1 +// + + +MidiOutPort_oss::MidiOutPort_oss(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_oss::MidiOutPort_oss(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::~MidiOutPort_oss +// + +MidiOutPort_oss::~MidiOutPort_oss() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiOutPort object count!: " << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::close +// + +void MidiOutPort_oss::close(void) { + // don't close anything, because the + // Linux driver keeps all of the ports open while the + // midi driver (/dev/sequencer) is running. +} + + + +////////////////////////////// +// +// MidiOutPort_oss::closeAll +// + +void MidiOutPort_oss::closeAll(void) { + // the Linux MIDI driver will close the /dev/sequencer device + // which will close all MIDI output ports at the same time. + Sequencer_oss::close(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getChannelOffset -- returns zero if MIDI channel +// offset is 0, or 1 if offset is 1. +// + +int MidiOutPort_oss::getChannelOffset(void) const { + return channelOffset; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getName -- returns the name of the port. +// returns "" if no name. Name is valid until getName is called again. +// + +const char* MidiOutPort_oss::getName(void) { + if (getPort() == -1) { + return "Null OSS MIDI Output"; + } + return getOutputName(getPort()); +} + + +const char* MidiOutPort_oss::getName(int i) { + return Sequencer_oss::getOutputName(i); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getNumPorts -- returns the number of available +// ports for MIDI output +// + +int MidiOutPort_oss::getNumPorts(void) { + return Sequencer_oss::getNumOutputs(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getPort -- returns the port to which this +// object belongs (as set with the setPort function). +// + +int MidiOutPort_oss::getPort(void) { + return port; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getPortStatus -- 0 if closed, 1 if open +// + +int MidiOutPort_oss::getPortStatus(void) { + // Linux MIDI devices are all open at the same time, + // so if one is open, then they all are. + return is_open(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::getTrace -- returns true if trace is on or +// false if off. If trace is on, then prints to standard output +// the Midi message being sent. +// + +int MidiOutPort_oss::getTrace(void) { + if (getPort() == -1) return -1; + + return trace[getPort()]; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::rawsend -- send the Midi command and its parameters +// + +int MidiOutPort_oss::rawsend(int command, int p1, int p2) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[3] = {(uchar)command, (uchar)p1, (uchar)p2}; + status = write(getPort(), mdata, 3); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << ":" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << "X" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_oss::rawsend(int command, int p1) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[2] = {(uchar)command, (uchar)p1}; + + status = write(getPort(), mdata, 2); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << ":" + << (int)mdata[1] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << std::dec << "X" + << (int)mdata[1] << "," << (int)mdata[2] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_oss::rawsend(int command) { + if (getPort() == -1) return 0; + + int status; + uchar mdata[1] = {(uchar)command}; + + status = write(getPort(), mdata, 1); + + if (getTrace()) { + if (status == 1) { + std::cout << "(" << std::hex << (int)mdata[0] << ")"; + std::cout.flush(); + } else { + std::cout << "(" << std::hex << (int)mdata[0] << ")"; + std::cout.flush(); + } + } + + return status; +} + + +int MidiOutPort_oss::rawsend(uchar* array, int size) { + if (getPort() == -1) return 0; + + int status; + status = write(getPort(), array, size); + + if (getTrace()) { + if (status == 1) { + std::cout << "(array)"; + std::cout.flush(); + } else { + std::cout << "(XarrayX)"; + std::cout.flush(); + } + } + + return status; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::open -- returns true if MIDI output port was +// opened. +// + +int MidiOutPort_oss::open(void) { + return Sequencer_oss::open(); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setChannelOffset -- sets the MIDI channel offset, +// either 0 or 1. +// + +void MidiOutPort_oss::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + std::cout << "Error: Channel offset can be only 0 or 1." << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setPort -- +// + +void MidiOutPort_oss::setPort(int aPort) { + if (aPort < -1 || aPort >= getNumPorts()) { + std::cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + if (port != -1) { + portObjectCount[port]++; + } +} + + + +////////////////////////////// +// +// MidiOutPort_oss::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_oss::setTrace(int aState) { + if (getPort() == -1) return -1; + + int oldtrace = trace[getPort()]; + if (aState == 0) { + trace[getPort()] = 0; + } else { + trace[getPort()] = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::sysex -- send a system exclusive message. +// The message must start with a 0xf0 byte and end with +// a 0xf7 byte. +// + +int MidiOutPort_oss::sysex(uchar* array, int size) { + if (size == 0 || array[0] != 0xf0) { + std::cout << "Error: invalid sysex message" << std::endl; + exit(1); + } + + return rawsend(array,size); +} + + + +////////////////////////////// +// +// MidiOutPort_oss::toggleTrace +// + +void MidiOutPort_oss::toggleTrace(void) { + if (getPort() == -1) return; + + trace[getPort()] = !trace[getPort()]; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_oss::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_oss::deinitialize(void) { + closeAll(); + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; + if (trace != NULL) delete [] trace; + trace = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_oss::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_oss::initialize(void) { + // get the number of ports + numDevices = getNumOutputs(); + if (getNumPorts() <= 0) { + std::cerr << "Warning: no MIDI output devices" << std::endl; + portObjectCount = NULL; + trace = NULL; + } else { + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + // allocate space for trace variable for each port: + if (trace != NULL) delete [] trace; + trace = new int[numDevices]; + + // initialize the static arrays + for (int i=0; i +// Creation Date: Mon Jan 12 21:40:35 GMT-0800 1998 +// Last Modified: Mon Jan 12 21:40:39 GMT-0800 1998 +// Filename: ...sig/code/control/MidiOutPort/unsupported/MidiOutPort_unsupported.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiOutPort_unsupported.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for basic MIDI output +// capabilities in an unknown operating system. Privately +// inherited by the MidiOutPort class. Used for compiling +// and running MIDI programs on a computer with no +// MIDI output. +// + +#include "MidiOutPort_unsupported.h" + +#include +#include +#include +#include + +// initialized static variables +int MidiOutPort_unsupported::numDevices = 0; +int MidiOutPort_unsupported::objectCount = 0; +int* MidiOutPort_unsupported::openQ = NULL; +int* MidiOutPort_unsupported::portObjectCount = NULL; +int MidiOutPort_unsupported::channelOffset = 0; + + +////////////////////////////// +// +// MidiOutPort_unsupported::MidiOutPort_unsupported +// default values: autoOpen = 1 +// + + +MidiOutPort_unsupported::MidiOutPort_unsupported(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_unsupported::MidiOutPort_unsupported(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::~MidiOutPort_unsupported +// + +MidiOutPort_unsupported::~MidiOutPort_unsupported() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + std::cerr << "Error: bad MidiOutPort object count!: " << objectCount << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::close +// + +void MidiOutPort_unsupported::close(void) { + if (getPortStatus() == 1) { + setPortStatus(0); + } +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::closeAll +// + +void MidiOutPort_unsupported::closeAll(void) { + for (int i=0; i= getNumPorts()) { + std::cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << std::endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + portObjectCount[port]++; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_unsupported::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::sysex -- +// + +int MidiOutPort_unsupported::sysex(uchar* array, int size) { + return 1; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::toggleTrace -- +// + +void MidiOutPort_unsupported::toggleTrace(void) { + trace = !trace; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_unsupported::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_unsupported::deinitialize(void) { + closeAll(); + if (openQ != NULL) delete [] openQ; + openQ = NULL; + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_unsupported::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_unsupported::initialize(void) { + // get the number of ports + numDevices = 16; + if (getNumPorts() <= 0) { + std::cerr << "Error: no MIDI output devices" << std::endl; + exit(1); + } + + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + + // initialize the static arrays + for (int i=0; i +// Creation Date: Sun Dec 28 15:18:46 GMT-0800 1997 +// Last Modified: Mon Jan 12 15:42:44 GMT-0800 1998 +// Last Modified: Tue Jun 29 13:10:30 PDT 1999 (verified sysex sending) +// Last Modified: Tue Jun 4 22:10:16 PDT 2002 (getNumPorts fix for static use) +// Filename: ...sig/code/control/MidiOutPort/visual/MidiOutPort_visual.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiOutPort_visual.cpp +// Syntax: C++ +// +// Description: Operating-System specific interface for +// basic MIDI output capabilities in Windows 95/NT/98 +// using winmm.lib. Privately inherited by the +// MidiOutPort class. +// + + +#ifdef VISUAL + +#include +#include "MidiOutPort_visual.h" + +typedef unsigned long ulong; +typedef unsigned char uchar; + + +// initialized static variables +int MidiOutPort_visual::numDevices = 0; +int MidiOutPort_visual::objectCount = 0; +int* MidiOutPort_visual::openQ = NULL; +int* MidiOutPort_visual::portObjectCount = NULL; +HMIDIOUT* MidiOutPort_visual::device = NULL; +int MidiOutPort_visual::channelOffset = 0; + + + +////////////////////////////// +// +// MidiOutPort_visual::MidiOutPort_visual +// default values: autoOpen = 1 +// + + +MidiOutPort_visual::MidiOutPort_visual(void) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(0); +} + + +MidiOutPort_visual::MidiOutPort_visual(int aPort, int autoOpen) { + if (objectCount == 0) { + initialize(); + } + objectCount++; + + port = -1; + setPort(aPort); + if (autoOpen) { + open(); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::~MidiOutPort_visual +// + +MidiOutPort_visual::~MidiOutPort_visual() { + objectCount--; + if (objectCount == 0) { + deinitialize(); + } else if (objectCount < 0) { + cerr << "Error: bad MidiOutPort object count!: " << objectCount << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::close +// + +void MidiOutPort_visual::close(void) { + if (getPort() == -1) { + return; + } + + if (getPortStatus() == 1 && device[getPort()] != NULL) { + + // The following function, midiOutClose, is not what I like. + // It will send note offs to any note which it thinks is + // on when the port is closed. Uncomment the line if + // you want this feature. + // midiOutReset(device[getPort()]); + + midiOutClose(device[getPort()]); + setPortStatus(0); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::closeAll +// + +void MidiOutPort_visual::closeAll(void) { + for (int i=0; i 64000 || size < 1) { + cerr << "Warning: cannot write a MIDI stream larger than 64kB" << endl; + return 0; + } + + MIDIHDR midiheader; // structure for sending an array of MIDI bytes + + midiheader.lpData = (char *)array; + midiheader.dwBufferLength = size; + // midiheader.dwBytesRecorded = size; // example program doesn't set + midiheader.dwFlags = 0; // flags must be set to 0 + + if (getPort() == -1) { + return -1; + } + + int status = midiOutPrepareHeader(device[getPort()], &midiheader, + sizeof(MIDIHDR)); + + if (status != MMSYSERR_NOERROR) { + return 0; + } + + status = midiOutLongMsg(device[getPort()], &midiheader, sizeof(MIDIHDR)); + + if (status != MMSYSERR_NOERROR) { + return 0; + } + + while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(device[getPort()], + &midiheader, sizeof(MIDIHDR))) { + Sleep(1); // sleep for 1 millisecond + } + + return 1; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::open -- returns true if MIDI output port was +// opened. +// + +int MidiOutPort_visual::open(void) { + if (getPort() == -1) { + return 2; + } + + if (getPortStatus() == 0) { + int flag; + flag = midiOutOpen(&device[getPort()], getPort(), 0, 0, CALLBACK_NULL); + if (flag == MMSYSERR_NOERROR) { + openQ[getPort()] = 1; + return 1; + } else { // faied to open + openQ[getPort()] = 0; + device[getPort()] = NULL; + return 0; + } + } else { // already open + return 1; + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setChannelOffset -- sets the MIDI channel offset, +// either 0 or 1. +// + +void MidiOutPort_visual::setChannelOffset(int anOffset) { + switch (anOffset) { + case 0: channelOffset = 0; break; + case 1: channelOffset = 1; break; + default: + cout << "Error: Channel offset can be only 0 or 1." << endl; + exit(1); + } +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setPort +// + +void MidiOutPort_visual::setPort(int aPort) { + if (aPort < 0 || aPort >= getNumPorts()) { + cerr << "Error: maximum port number is: " << getNumPorts()-1 + << ", but you tried to access port: " << aPort << endl; + exit(1); + } + + if (port != -1) { + portObjectCount[port]--; + } + port = aPort; + portObjectCount[port]++; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::setTrace -- if false, then won't print +// Midi messages to standard output. +// + +int MidiOutPort_visual::setTrace(int aState) { + int oldtrace = trace; + if (aState == 0) { + trace = 0; + } else { + trace = 1; + } + return oldtrace; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::sysex -- send a system exclusive message. +// The first byte of the message must be a 0xf0 byte. +// + +int MidiOutPort_visual::sysex(uchar* array, int size) { + if (size == 0 || array[0] != 0xf0) { + cout << "Error: invalid system exclusive message," + " first byte must be 0xf0" << endl; + exit(1); + } + + return rawsend(array, size); +} + + + +////////////////////////////// +// +// MidiOutPort_visual::toggleTrace +// + +void MidiOutPort_visual::toggleTrace(void) { + trace = !trace; +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Private functions +// + + + +////////////////////////////// +// +// MidiOutPort_visual::deinitialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_visual::deinitialize(void) { + closeAll(); + if (device != NULL) delete [] device; + device = NULL; + if (openQ != NULL) delete [] openQ; + openQ = NULL; + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = NULL; +} + + + +////////////////////////////// +// +// MidiOutPort_visual::initialize -- sets up storage if necessary +// This function should be called if the current object is +// the first object to be created. +// + +void MidiOutPort_visual::initialize(void) { + // get the number of ports + numDevices = midiOutGetNumDevs(); + if (getNumPorts() <= 0) { + cerr << "Error: no MIDI output devices" << endl; + exit(1); + } + + // allocate space for Windoze MIDI output structures + if (device != NULL) { + cerr << "Error: device array should be NULL when calling " + << "initialize() in MidiOutPort." << endl; + exit(1); + } + device = new HMIDIOUT[numDevices]; + + // allocate space for openQ, the port open/close status + if (openQ != NULL) delete [] openQ; + openQ = new int[numDevices]; + + // allocate space for object count on each port: + if (portObjectCount != NULL) delete [] portObjectCount; + portObjectCount = new int[numDevices]; + + + // initialize the static arrays + for (int i=0; i +// Creation Date: 18 December 1997 +// Last Modified: Mon Jan 26 23:54:36 GMT-0800 1998 +// Last Modified: Tue Feb 2 08:30:28 PST 1999 +// Last Modified: Sun Jul 18 18:52:29 PDT 1999 (added RPN functions) +// Last Modified: Sun Dec 9 15:01:33 PST 2001 (switched con/des code) +// Filename: ...sig/code/control/MidiOutput/MidiOutput.cpp +// Web Address: http://sig.sapp.org/src/sig/MidiOutput.cpp +// Syntax: C++ +// +// Description: The MIDI output interface for MIDI synthesizers/equipment +// which has many convienience functions defined for +// various types of MIDI output. +// + +#include "MidiOutput.h" +#include +#include + +#define RECORD_ASCII (0) +#define RECORD_BINARY (1) +#define RECORD_MIDI_FILE (2) + + +// declaration of static variables +SigTimer MidiOutput::timer; +Array* MidiOutput::rpn_lsb_status = NULL; +Array* MidiOutput::rpn_msb_status = NULL; +int MidiOutput::objectCount = 0; + + +////////////////////////////// +// +// MidiOutput::MidiOutput -- +// + + +MidiOutput::MidiOutput(void) : MidiOutPort() { + outputRecordQ = 0; + + if (objectCount == 0) { + initializeRPN(); + } + objectCount++; +} + + + +MidiOutput::MidiOutput(int aPort, int autoOpen) : MidiOutPort(aPort, autoOpen) { + outputRecordQ = 0; + + if (objectCount == 0) { + initializeRPN(); + } + objectCount++; +} + + + +////////////////////////////// +// +// MidiOutput::~MidiOutput +// + +MidiOutput::~MidiOutput() { + objectCount--; + if (objectCount == 0) { + deinitializeRPN(); + } else if (objectCount < 0) { + std::cout << "Error in MidiOutput decontruction" << std::endl; + } + +} + + + +////////////////////////////// +// +// MidiOutput::cont -- send a controller command MIDI message. +// +// channel = the Midi channel ofset from 0 [0..15] +// controller = the continuous controller number [0..127] +// data = the value of the specified controller [0..127] +// + +int MidiOutput::cont(int channel, int controller, int data) { + return send(0xb0 | (channel & 0x0f), controller, data); +} + + + +////////////////////////////// +// +// MidiOutput::off -- sends a Note Off MIDI message (0x80). +// +// channel = MIDI channel to send note on. range is [0..15] +// keynum = MIDI key number to play (middle C = 60, C# = 61, etc.) [0..127] +// velocity = release velocity of the note, 127 = quickest possible +// +// Note: The more common method of turning off a note is to use the +// play() function (midi command 0x90) but send an attack velocity of 0. +// + +int MidiOutput::off(int channel, int keynum, int releaseVelocity) { + return send(0x80 | (channel & 0x0f), keynum, releaseVelocity); +} + + + +////////////////////////////// +// +// MidiOutput::pc -- send a patch change MIDI message. changes the timbre +// on the specified channel. +// +// channel = MIDI channel to which to send the patch change [0..15] +// timbre = the voice to select on the specified channel [0..127] +// + +int MidiOutput::pc(int channel, int timbre) { + return send(0xc0 | (channel & 0x0f), timbre); +} + + + +////////////////////////////// +// +// MidiOutput::play -- sends a Note On/Off MIDI message. +// +// channel = MIDI channel to send note on. range is [0..15] +// keynum = MIDI key number to play (middle C = 60, C# = 61, etc.) [0..127] +// velocity = attack velocity of the note, 0 = 0ff, 127 = loudest possible +// + +int MidiOutput::play(int channel, int keynum, int velocity) { + return send(0x90 | (channel & 0x0f), keynum, velocity); +} + + + +////////////////////////////// +// +// MidiOutput::pw -- Pitch Wheel: send a MIDI pitch bend. +// Parameters are: +// 1. channel -- MIDI channel offset from 0. +// 2. mostByte -- most significant 7 bits (coarse tuning) +// 3. leastByte -- least significant 7 bits (fine tuning) +// + +int MidiOutput::pw(int channel, int mostByte, int leastByte) { + return send(0xe0 | (channel & 0x0f), leastByte, mostByte); +} + + + +////////////////////////////// +// +// MidiOutput::pw -- Pitch Wheel: 14 bit number given as input +// range for 14 bit number is 0 to 16383. +// + +int MidiOutput::pw(int channel, int tuningData) { + uchar greaterBits = (uchar)((tuningData >> 7) & 0x7f); + uchar lesserBits = (uchar)(tuningData & 0x7f); + return pw(channel, greaterBits, lesserBits); +} + + + +////////////////////////////// +// +// MidiOutput::pw -- Pitch Wheel: range between -1 to 1 given as input. +// Range is then converted to a 14 bit number. +// +1 = highest value of pitch wheel +// 0 = rest position of pitch wheel +// -1 = lowest value of pitch wheel +// + +int MidiOutput::pw(int channel, double tuningData) { + if (tuningData < -1.0 || tuningData > 1.0) { + std::cerr << "Error: pitch wheel data is out of range: " << tuningData << std::endl; + exit(1); + } + + int output = (int)((tuningData+1.0)/2.0*16383 + 0.5); + return pw(channel, output); +} + + + +////////////////////////////// +// +// MidiOutput::recordStart +// + +void MidiOutput::recordStart(char *filename, int format) { + if (outputRecordQ) { // already recording, so close old file + recordStop(); + } + + outputRecordFile.open(filename, std::ios::out); + if (!outputRecordFile) { // open file failed + std::cerr << "Error: cannot open file " << filename << std::endl; + outputRecordQ = 0; + } else { + outputRecordQ = 1; + } + + if (outputRecordQ) { + switch (format) { + case RECORD_ASCII: // ascii + outputRecordType = RECORD_ASCII; + outputRecordFile <<"; delta time/MIDI output at delta time" << std::endl; + break; + case RECORD_BINARY: // binary + outputRecordType = RECORD_BINARY; + // record the magic number for binary format + outputRecordFile << (uchar)0xf8 << (uchar)0xf8 + << (uchar)0xf8 << (uchar)0xf8; + break; + case RECORD_MIDI_FILE: // standard MIDI file, type 0 + default: + outputRecordType = RECORD_MIDI_FILE; + // header stuff to be written here + break; + } + } + + lastFlushTime = timer.getTime(); +} + + + +////////////////////////////// +// +// MidiOutput::recordStop +// + +void MidiOutput::recordStop(void) { + if (outputRecordQ) { + outputRecordQ = 0; + outputRecordFile.close(); + } +} + + + +////////////////////////////// +// +// MidiOutput::reset -- sends the MIDI command 0xFF which +// should force the MIDI devices on the other side of the +// MIDI cable into their power-on reset condition, clear running +// status, turn off any sounding notes, set Local Control on, and +// otherwise clean up the state of things. +// + +void MidiOutput::reset(void) { + send(0xff, 0, 0); +} + + + +////////////////////////////// +// +// MidiOutput::send -- send a byte to the MIDI port but record it +// first. +// + +int MidiOutput::send(int command, int p1, int p2) { + if (outputRecordQ) { + switch (outputRecordType) { + case 0: // ascii + writeOutputAscii(command, p1, p2); + break; + case 1: // binary + writeOutputBinary(command, p1, p2); + break; + case 2: // standard MIDI file type 0 + writeOutputMidifile(command, p1, p2); + break; + } + lastFlushTime = timer.getTime(); // only keep track if recording + } + return rawsend(command, p1, p2); +} + + +int MidiOutput::send(int command, int p1) { + if (outputRecordQ) { + switch (outputRecordType) { + case 0: // ascii + writeOutputAscii(command, p1, -1); + break; + case 1: // binary + writeOutputBinary(command, p1, -1); + break; + case 2: // standard MIDI file type 0 + writeOutputMidifile(command, p1, -1); + break; + } + lastFlushTime = timer.getTime(); // only keep track if recording + } + return rawsend(command, p1); +} + + +int MidiOutput::send(int command) { + if (outputRecordQ) { + switch (outputRecordType) { + case 0: // ascii + writeOutputAscii(command, -1, -1); + break; + case 1: // binary + writeOutputBinary(command, -1, -1); + break; + case 2: // standard MIDI file type 0 + writeOutputMidifile(command, -1, -1); + break; + } + lastFlushTime = timer.getTime(); // only keep track if recording + } + return rawsend(command); +} + + + +////////////////////////////// +// +// MidiOutput::silence -- send a note off to all notes on all channels. +// default value: aChannel = -1 +// + +void MidiOutput::silence(int aChannel) { + int keyno; + if (aChannel == -1) { + for (int channel=0; channel<16; channel++) { + for (keyno=0; keyno<128; keyno++) { + play(channel, keyno, 0); + } + } + } else { + for (keyno=0; keyno<128; keyno++) { + play(aChannel, keyno, 0); + } + } +} + + + +////////////////////////////// +// +// MidiOutput::sustain -- set the MIDI sustain continuous controller on or off. +// Equivalent to the command cont(channel, 0x40, status). +// + +void MidiOutput::sustain(int channel, int status) { + if (status) { // turn on sustain + cont(channel, 0x40, 127); + } else { // turn off sustain + cont(channel, 0x40, 0); + } +} + + + +/////////////////////////////// +// +// MidiOutput::sysex -- sends a system exclusive MIDI message. +// you must supply the 0xf0 at the start of the array +// and the 0xf7 at the end of the array. +// + +int MidiOutput::sysex(char* data, int length) { + return rawsend((uchar*)data, length); +} + + +int MidiOutput::sysex(uchar* data, int length) { + return rawsend(data, length); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// RPN functions +// + + +////////////////////////////// +// +// NRPN -- sends a Non-registered parameter number where: +// parameter #1: channel (0-15) +// parameter #2: NRPN MSB indicator (controller #99 data) +// parameter #3: NRPN LSB indicator (controller #98 data) +// parameter #4: NRPN MSB data (controller #6 data) +// [parameter #5: NRPN LSB data (controller #38 data)] +// or: +// parameter #1: channel (0-15) +// parameter #2: NRPN MSB indicator (controller #99 data) +// parameter #3: NRPN LSB indicator (controller #98 data) +// parameter #4: NRPN Floating point in range (-1..1) (ccont#6 and #38 data) +// +// +// NRPN (Non-registered parameter number) -- General MIDI and +// Extended MIDI mess. It becomes the receiving synthesizer's +// responsibility to determine the meaning of continuous +// controller (ccont) #6 from data sent with cconts #98,99 (for +// NRPNS) and cconts #100,101 (for RPNS). NRPN parameters +// are not reset when the ccont#121 is sent to reset controllers. +// +// NRPN's are "non-standard" meaning that any synthesizer could +// do whatever they want with a given NRPN; However, the +// GS and XG specifications are given in the table further below. +// +// The data for NRPNs are transfered to synthesizer with +// data slider ccont #6(MSB) and ccont #38(LSB). Also data increment +// ccont#96 (data increment) and ccont#97 (data decrement) are in +// relation to the RPN or NRPN in effect. Increment and Decrement +// are not recommend to use with RPN's because of confusion in the +// MIDI industry over which 7-bit data (#6 or #38) to increment. +// +// Once you have selected an NRPN on a given channel, the +// channel will apply subsequent Data Entry to the +// selected parameter. After making the necessary settings +// you should set NRPN to NULL to reduce the risk of +// operational errors. a NUL RPN will disable the previous +// values of either RPN or NRPN data. +// +// The following NRPN values are supported in Yamaha's XG specification: +// CCont #98 = LSB of NRPN parameter ID +// CCont #99 = MSB of NRPN parameter ID +// +// NRPN +// MSB LSB Data Range +// #99 #98 Parameter (ccont#6=MSB, ccont#38=LSB) +// === ===== ====================== ====================== +// 1 8 Vibrato Rate -64.. 0..+63 logical range or (-50..+50) +// 0..64..127 MIDI data range ( 14..114) +// 1 9 Vibrato Depth same ranges as above +// 1 10 Vibrato Delay same ranges as above +// 1 32 Filter Cutoff Freq. same ranges as above +// 1 33 Filter Resonance same ranges as above +// 1 99 EG Attack Time same ranges as above +// 1 100 EG Decay Time same ranges as above +// 1 102 EG Release Time same ranges as above +// 20 xx Drum Filter Cutoff Freq same ranges as above +// xx = drum MIDI key number +// 21 xx Drum Filter Resonance same ranges as above +// xx = drum MIDI key number +// 22 xx Drum EG Attack Rage same ranges as above +// xx = drum MIDI key number +// 23 xx Drum EG Decay Rate same ranges as above +// xx = drum MIDI key number +// 24 xx Drum Pitch Coarse same ranges as above +// xx = drum MIDI key number +// 25 xx Drum Pitch Fine same ranges as above +// xx = drum MIDI key number +// 26 xx Drum Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 28 xx Drum Pan Random, Left..Center..Right +// 0.......1.....64......127 MIDI data range +// xx = drum MIDI key number +// 29 xx Drum Reverb Send Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 30 xx Drum Chorus Send Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 31 xx Drum Variation Send Level 0..64..127 MIDI data range +// xx = drum MIDI key number +// 127 127 Null RPN (disables RPN/NRPN parameters from being altered). +// +// + +int MidiOutput::NRPN(int channel, int nrpn_msb, int nrpn_lsb, + int data_msb, int data_lsb) { + channel = channel & 0x0f; + nrpn_msb = nrpn_msb & 0x7f; + nrpn_lsb = nrpn_msb & 0x7f; + data_msb = nrpn_msb & 0x7f; + data_lsb = nrpn_msb & 0x7f; + + int status = 1; + + // check to see if the nrpn_msb and nrpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != nrpn_msb) { + status &= cont(channel, 99, nrpn_msb); + rpn_msb_status[getPort()][channel] = nrpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != nrpn_lsb) { + status &= cont(channel, 98, nrpn_lsb); + rpn_lsb_status[getPort()][channel] = nrpn_lsb; + } + + // now that the NRPN state is set, send the NRPN data values + // but do not bother sending any data if the Null RPN is in effect. + if (nrpn_msb != 127 && nrpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + status &= cont(channel, 38, data_msb); + } + + return status; +} + + +int MidiOutput::NRPN(int channel, int nrpn_msb, int nrpn_lsb, int data_msb) { + channel = channel & 0x0f; + nrpn_msb = nrpn_msb & 0x7f; + nrpn_lsb = nrpn_msb & 0x7f; + data_msb = nrpn_msb & 0x7f; + + int status = 1; + + // check to see if the nrpn_msb and nrpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != nrpn_msb) { + status &= cont(channel, 99, nrpn_msb); + rpn_msb_status[getPort()][channel] = nrpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != nrpn_lsb) { + status &= cont(channel, 98, nrpn_lsb); + rpn_lsb_status[getPort()][channel] = nrpn_lsb; + } + + // now that the NRPN state is set, send the NRPN data value, + // but do not bother sending any data if the Null RPN is in effect. + if (nrpn_msb != 127 && nrpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + } + + return status; +} + + +int MidiOutput::NRPN(int channel, int nrpn_msb, int nrpn_lsb, double data) { + channel = channel & 0x0f; + nrpn_msb = nrpn_msb & 0x7f; + nrpn_lsb = nrpn_msb & 0x7f; + if (data < -1.0) { + data = -1.0; + } else if (data > 1.0) { + data = 1.0; + } + + int status = 1; + + // check to see if the nrpn_msb and nrpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != nrpn_msb) { + status &= cont(channel, 99, nrpn_msb); + rpn_msb_status[getPort()][channel] = nrpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != nrpn_lsb) { + status &= cont(channel, 98, nrpn_lsb); + rpn_lsb_status[getPort()][channel] = nrpn_lsb; + } + + // convert data into 14 bit number + int data14 = (int)((data+1.0)/2.0*16383 + 0.5); + + // send the NRPN data values, two message of 7 bits each + // but do not bother sending any data if the Null RPN is in effect. + if (nrpn_msb != 127 && nrpn_lsb != 127) { + status &= cont(channel, 6, data14 >> 7); + status &= cont(channel, 38, data14 & 0x7f); + } + + return status; +} + + +////////// +// +// Convenience functions for use of NRPN function. Note that these +// are "Non-Registered" Parameter Numbers which means that each +// synthesizer manufacture can do whatever they want, so these +// functions might not behave the way you expect them to do so. +// Yamaha XG and Roland GS NRPN specifications are given below. +// + +int MidiOutput::NRPN_null(int channel) { + return NRPN(channel, 127, 127, 0); +} + +int MidiOutput::NRPN_vibratoRate(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 8, value+64); +} + +int MidiOutput::NRPN_vibratoRate(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 8, value); +} + +int MidiOutput::NRPN_vibratoDepth(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 9, value+64); +} + +int MidiOutput::NRPN_vibratoDepth(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 9, value); +} + +int MidiOutput::NRPN_vibratoDelay(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 32, value+64); +} + +int MidiOutput::NRPN_vibratoDelay(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 32, value); +} + +int MidiOutput::NRPN_filterCutoff(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 33, value+64); +} + +int MidiOutput::NRPN_filterCutoff(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 33, value); +} + +int MidiOutput::NRPN_attack(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 99, value+64); +} + +int MidiOutput::NRPN_attack(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 99, value); +} + +int MidiOutput::NRPN_decay(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 100, value+64); +} + +int MidiOutput::NRPN_decay(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 100, value); +} + +int MidiOutput::NRPN_release(int channel, int value) { + // value in range -64..+63 + return NRPN(channel, 1, 102, value+64); +} + +int MidiOutput::NRPN_release(int channel, double value) { + // value in range -1.0..+1.0 + return NRPN(channel, 1, 102, value); +} + +int MidiOutput::NRPN_drumFilterCutoff(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 20, drum, value+64); +} + +int MidiOutput::NRPN_drumFilterCutoff(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 20, drum, value); +} + +int MidiOutput::NRPN_drumFilterResonance(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 21, drum, value+64); +} + +int MidiOutput::NRPN_drumFilterResonance(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 21, drum, value); +} + +int MidiOutput::NRPN_drumAttack(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 22, drum, value+64); +} + +int MidiOutput::NRPN_drumAttack(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 22, drum, value); +} + +int MidiOutput::NRPN_drumDecay(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 23, drum, value+64); +} + +int MidiOutput::NRPN_drumDecay(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 23, drum, value); +} + +int MidiOutput::NRPN_drumPitch(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 24, drum, value+64); +} + +int MidiOutput::NRPN_drumPitch(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 24, drum, value); +} + +int MidiOutput::NRPN_drumLevel(int drum, int value) { + // value in range -64..+63 + return NRPN(9, 26, drum, value+64); +} + +int MidiOutput::NRPN_drumLevel(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 26, drum, value); +} + +int MidiOutput::NRPN_drumPan(int drum, int value) { + return NRPN(9, 28, drum, value+64); +} + +int MidiOutput::NRPN_drumPan(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 28, drum, value); +} + +int MidiOutput::NRPN_drumReverb(int drum, int value) { + // note offset from 0 not -64 + return NRPN(9, 29, drum, value); +} + +int MidiOutput::NRPN_drumReverb(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 29, drum, value); +} + +int MidiOutput::NRPN_drumChorus(int drum, int value) { + // note offset from 0 not -64 + return NRPN(9, 30, drum, value); +} + +int MidiOutput::NRPN_drumChorus(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 30, drum, value); +} + +int MidiOutput::NRPN_drumVariation(int drum, int value) { + // note offset from 0 not -64 + return NRPN(9, 31, drum, value); +} + +int MidiOutput::NRPN_drumVariation(int drum, double value) { + // value in range -1.0..+1.0 + return NRPN(9, 31, drum, value); +} + +// +// Convenience functions for use of NRPN function. +// +////////// + + + +////////////////////////////// +// +// RPN -- sends a registered parameter number where: +// parameter #1: channel (0-15) +// parameter #2: RPN MSB indicator (controller #101 data) +// parameter #3: RPN LSB indicator (controller #100 data) +// parameter #4: RPN MSB data (controller #6 data) +// [parameter #5: RPN LSB data (controller #38 data)] +// or: +// parameter #1: channel (0-15) +// parameter #2: NRPN MSB indicator (controller #99 data) +// parameter #3: NRPN LSB indicator (controller #98 data) +// parameter #4: NRPN Floating point in range (-1..1) (ccont#6 and #38 data) +// +// +// RPN (registered parameter number) -- General MIDI and +// Extended MIDI mess. It becomes the receiving synthesizer's +// responsibility to determine the meaning of continuous +// controller (ccont) #6 from data sent with cconts #100,101 (for +// RPNS) and cconts #98,99 (for NRPNS). +// +// The data for RPNs are transfered to synthesizer with +// data slider ccont #6(MSB) and ccont #38(LSB). Also data increment +// ccont#96 (data increment) and ccont#97 (data decrement) are in +// relation to the RPN or NRPN in effect. Increment and Decrement +// are not recommend to use with RPN's because of confusion in the +// MIDI industry over which 7-bit data (#6 or #38) to increment. +// +// Once you have selected an RPN on a given channel, the +// channel will apply subsequent Data Entry to the +// selected parameter. After making the necessary settings +// you should set RPN's to NULL to reduce the risk of +// operational errors. a NULL RPN will disable the previous +// values of either RPN or NRPN data. +// +// The following RPN values are registered: +// CCont #100 = LSB of RPN parameter ID +// CCont #101 = MSB of RPN parameter ID +// +// RPN Data Range +// MSB LSB Parameter (ccont#6=MSB, ccont#38=LSB) +// === ===== ====================== ====================== + +// 0 0 Pitchbend Sensitivity 0-127 (default 2) (LSB ignored) +// (The number of +/- half steps in +// pitch wheel range). +// 0 1 Fine Tune -64.. 0..+63 logical range +// 0..64..127 MIDI data range +// 0 2 Coarse Tune same range as above. +// 0 3 Change Tuning Program 0..127 +// 0 4 Change Tuning Bank 0..127 +// + +int MidiOutput::RPN(int channel, int rpn_msb, int rpn_lsb, + int data_msb, int data_lsb) { + channel = channel & 0x0f; + rpn_msb = rpn_msb & 0x7f; + rpn_lsb = rpn_msb & 0x7f; + data_msb = rpn_msb & 0x7f; + data_lsb = rpn_msb & 0x7f; + + int status = 1; + + // check to see if the rpn_msb and rpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != rpn_msb) { + status &= cont(channel, 101, rpn_msb); + rpn_msb_status[getPort()][channel] = rpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != rpn_lsb) { + status &= cont(channel, 100, rpn_lsb); + rpn_lsb_status[getPort()][channel] = rpn_lsb; + } + + // now that the RPN state is set, send the RPN data values + // but do not bother sending any data if the Null RPN is in effect. + if (rpn_msb != 127 && rpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + status &= cont(channel, 38, data_msb); + } + + return status; +} + + +int MidiOutput::RPN(int channel, int rpn_msb, int rpn_lsb, int data_msb) { + channel = channel & 0x0f; + rpn_msb = rpn_msb & 0x7f; + rpn_lsb = rpn_msb & 0x7f; + data_msb = rpn_msb & 0x7f; + + int status = 1; + + // check to see if the rpn_msb and rpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != rpn_msb) { + status &= cont(channel, 101, rpn_msb); + rpn_msb_status[getPort()][channel] = rpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != rpn_lsb) { + status &= cont(channel, 100, rpn_lsb); + rpn_lsb_status[getPort()][channel] = rpn_lsb; + } + + // now that the RPN state is set, send the RPN data value, + // but do not bother sending any data if the Null RPN is in effect. + if (rpn_msb != 127 && rpn_lsb != 127) { + status &= cont(channel, 6, data_msb); + } + + return status; +} + + +int MidiOutput::RPN(int channel, int rpn_msb, int rpn_lsb, double data) { + channel = channel & 0x0f; + rpn_msb = rpn_msb & 0x7f; + rpn_lsb = rpn_msb & 0x7f; + if (data < -1.0) { + data = -1.0; + } else if (data > 1.0) { + data = 1.0; + } + + int status = 1; + + // check to see if the rpn_msb and rpn_lsb are the same + // as the last call to this function, if not, then send + // the appropriate MIDI controller values. + if (rpn_msb_status[getPort()][channel] != rpn_msb) { + status &= cont(channel, 101, rpn_msb); + rpn_msb_status[getPort()][channel] = rpn_msb; + } + if (rpn_lsb_status[getPort()][channel] != rpn_lsb) { + status &= cont(channel, 100, rpn_lsb); + rpn_lsb_status[getPort()][channel] = rpn_lsb; + } + + // convert data into 14 bit number + int data14 = (int)((data+1.0)/2.0*16383 + 0.5); + + // send the RPN data values, two message of 7 bits each + // but do not bother sending any data if the Null RPN is in effect. + if (rpn_msb != 127 && rpn_lsb != 127) { + status &= cont(channel, 6, data14 >> 7); + status &= cont(channel, 38, data14 & 0x7f); + } + + return status; +} + + +////////// +// +// Convenience functions for use of RPN function. +// + +int MidiOutput::RPN_null(void) { + int status = 1; + for (int i=0; i<16; i++) { + status &= RPN_null(i); + } + return status; +} + +int MidiOutput::RPN_null(int channel) { + return RPN(channel, 127, 127, 0); +} + +int MidiOutput::pbRange(int channel, int steps) { + // default value for pitch bend sensitivity is 2 semitones. + return RPN(channel, 0, 0, steps); +} + +int MidiOutput::tuneFine(int channel, int cents) { + // data from -64 to + 63 + return RPN(channel, 0, 1, cents+64); +} + +int MidiOutput::fineTune(int channel, int cents) { + return tuneFine(channel, cents); +} + +int MidiOutput::tuneCoarse(int channel, int steps) { + // data from -64 to + 63 + return RPN(channel, 0, 1, steps+64); +} + +int MidiOutput::coarseTune(int channel, int steps) { + return tuneCoarse(channel, steps); +} + +int MidiOutput::tuningProgram(int channel, int program) { + return RPN(channel, 0, 3, program); +} + +int MidiOutput::tuningBank(int channel, int bank) { + return RPN(channel, 0, 4, bank); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// private functions +// + + +////////////////////////////// +// +// MidiOutput::initializeRPN -- set up the RPN status arrays +// ignores initiaization request if already initialized. +// + +void MidiOutput::initializeRPN(void) { + int i, channel; + + if (rpn_lsb_status == NULL) { + rpn_lsb_status = new Array[getNumPorts()]; + for (i=0; i[getNumPorts()]; + for (i=0; i +// Creation Date: 21 December 1997 +// Last Modified: Fri Jan 23 10:24:35 GMT-0800 1998 +// Filename: .../sig/code/control/MidiPort/MidiPort.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/MidiPort.cpp +// Syntax: C++ +// +// Description: A unified object that handles basic MIDI input and output. +// Derived from the MidiInPort and MidiOutPort classes. +// + +#include "MidiPort.h" + + +////////////////////////////// +// +// MidiPort::MidiPort +// + +MidiPort::MidiPort(void) : MidiOutPort(), MidiInPort() { + // nothing +} + + +MidiPort::MidiPort(int outputPort, int inputPort) : + MidiOutPort(outputPort), MidiInPort(inputPort) { + // nothing +} + + + +////////////////////////////// +// +// MidiPort::~MidiPort +// + +MidiPort::~MidiPort() { + // nothing +} + + + +////////////////////////////// +// +// MidiPort::getChannelInOffset -- return the MIDI channel offset of +// the MIDI input. +// + +int MidiPort::getChannelInOffset(void) const { + return MidiInPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiPort::getChannelOutOffset -- return the MIDI channel offset of +// the MIDI output. +// + +int MidiPort::getChannelOutOffset (void) const { + return MidiOutPort::getChannelOffset(); +} + + + +////////////////////////////// +// +// MidiPort::getInputPort +// + +int MidiPort::getInputPort(void) { + return MidiInPort::getPort(); +} + + + +////////////////////////////// +// +// MidiPort::getInputTrace +// + +int MidiPort::getInputTrace(void) { + return MidiInPort::getTrace(); +} + + + +////////////////////////////// +// +// MidiPort::getOutputPort +// + +int MidiPort::getOutputPort(void) { + return MidiOutPort::getPort(); +} + + + +////////////////////////////// +// +// MidiPort::getOutputTrace +// + +int MidiPort::getOutputTrace(void) { + return MidiOutPort::getTrace(); +} + + + +////////////////////////////// +// +// MidiPort::setChannelOffset -- sets the MIDI channel offset +// + +void MidiPort::setChannelOffset(int anOffset) { + MidiInPort::setChannelOffset(anOffset); + MidiOutPort::setChannelOffset(anOffset); +} + + + +////////////////////////////// +// +// MidiPort::setInputPort +// + +void MidiPort::setInputPort(int aPort) { + MidiInPort::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiPort::setInputTrace +// + +int MidiPort::setInputTrace(int aState) { + return MidiInPort::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiPort::setOutputPort +// + +void MidiPort::setOutputPort(int aPort) { + MidiOutPort::setPort(aPort); +} + + + +////////////////////////////// +// +// MidiPort::setOutputTrace +// + +int MidiPort::setOutputTrace(int aState) { + return MidiOutPort::setTrace(aState); +} + + + +////////////////////////////// +// +// MidiPort::toggleInputTrace +// + +void MidiPort::toggleInputTrace(void) { + MidiInPort::toggleTrace(); +} + + +////////////////////////////// +// +// MidiPort::toggleOutputTrace +// + +void MidiPort::toggleOutputTrace(void) { + MidiOutPort::toggleTrace(); +} + + + +// md5sum: c2583f3ed21e238ba6b298915cb728aa - MidiPort.cpp =css= 20030102 diff --git a/src/midiio/src/Options.cpp b/src/midiio/src/Options.cpp new file mode 100644 index 0000000..0341fe3 --- /dev/null +++ b/src/midiio/src/Options.cpp @@ -0,0 +1,887 @@ +// +// Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sat Mar 27 18:17:06 PST 1999 +// Last Modified: Thu Apr 13 14:02:52 PDT 2000 (added 2nd define function) +// Last Modified: Fri May 5 17:52:01 PDT 2000 (added --options suppression) +// Last Modified: Tue May 1 01:25:58 PDT 2001 (fixed getArgumentCount()) +// Filename: ...sig/maint/code/sigBase/Options.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Options.cpp +// Documentation: http://sig.sapp.org/doc/classes/Options +// Syntax: C++ +// +// Description: Handles command-line options in a graceful manner. +// + +int optionListCompare(const void* a, const void* b); + +#include "Options.h" +#include "Options_private.h" +#include +#include +#include +#include + + +////////////////////////////// +// +// Options::Options -- +// + +Options::Options(void) { + optionFlag = '-'; + gargc = -1; + gargv = NULL; + argument.setSize(0); + argument.allowGrowth(); + optionRegister.setSize(0); + optionRegister.allowGrowth(); + optionList.setSize(0); + optionList.allowGrowth(); + processedQ = 0; + sortedQ = 0; + commandString = NULL; + options_error_check = 1; + suppressQ = 0; + optionsArgument = 0; +} + + +Options::Options(int argc, char** argv) { + optionFlag = '-'; + gargc = -1; + gargv = NULL; + argument.setSize(0); + argument.allowGrowth(); + optionRegister.setSize(0); + optionRegister.allowGrowth(); + optionList.setSize(0); + optionList.allowGrowth(); + processedQ = 0; + sortedQ = 0; + commandString = NULL; + options_error_check = 1; + suppressQ = 0; + optionsArgument = 0; + + setOptions(argc, argv); +} + + + +////////////////////////////// +// +// Options::~Options -- +// + +Options::~Options() { + reset(); +} + + + +////////////////////////////// +// +// Options::argc -- returns the argument count as from main(). +// + +int Options::argc(void) const { + return gargc; +} + + + +////////////////////////////// +// +// Options::argv -- returns the arguments strings as from main(). +// + +char** Options::argv(void) const { + return gargv; +} + + + +////////////////////////////// +// +// Options::define -- define an option entry in the option register +// + +void Options::define(const char* aDefinition) { + sortedQ = 0; // have to sort option list later + option_register* definitionEntry; + option_list* optionListEntry; + + + // error if the definition string doesn't contain an equals sign. + if (strchr(aDefinition, '=') == NULL) { + std::cout << "Error: no \"=\" in option definition: " << aDefinition << std::endl; + exit(1); + } + + // get the length of the definition string + int len = strlen(aDefinition); + + // put space before and after the equals sign so that strtok works + char* definitionString; + definitionString = new char[len + 3]; + int i = 0; + while (aDefinition[i] != '=' && i < len) { + definitionString[i] = aDefinition[i]; + i++; + } + definitionString[i] = ' '; + i++; + definitionString[i] = '='; + i++; + definitionString[i] = ' '; + for (int k=i; ksetType(optionType); + i++; + + + // check to make sure that the type is correct. + if (optionType != OPTION_STRING_TYPE && + optionType != OPTION_INT_TYPE && + optionType != OPTION_FLOAT_TYPE && + optionType != OPTION_DOUBLE_TYPE && + optionType != OPTION_BOOLEAN_TYPE && + optionType != OPTION_CHAR_TYPE ) { + std::cout << "Error: unknown option type \'" << optionType + << "\' in defintion: " << aDefinition << std::endl; + exit(1); + } + + // skip any white space after option type. + while (isspace(definitionString[i]) && i < len) { + i++; + } + + + // there can only be two characters now: '\0' or ':' + if (i >= len || definitionString[i] == '\0') { + goto option_finish; + } else if (i= len || definitionString[i] == '\0') { + goto option_finish; + } + + + // now at beginnng of default option string which continues + // until the end of the definition string. + definitionEntry->setDefault(&definitionString[i]); + +option_finish: + + optionRegister.append(definitionEntry); + + + delete [] definitionString; + delete [] tempstr; + +} + + +void Options::define(const char* aDefinition, const char* description) { + define(aDefinition); + + // now find some place to store the description... +} + + + +////////////////////////////// +// +// Options::getArg -- returns the specified argument. +// argurment 0 is the command name. +// + +char* Options::getArg(int index) { + if (index < 0 || index >= argument.getSize()) { + std::cout << "Error: argument " << index << " does not exist." << std::endl; + exit(1); + } + return argument[index]; +} + + + +////////////////////////////// +// +// Options::getArgument -- same as getArg +// + +char* Options::getArgument(int index) { + return getArg(index); +} + + + +////////////////////////////// +// +// Options::getArgCount -- number of arguments on command line. +// does not count the options or the command name. +// + +int Options::getArgCount(void) { + return argument.getSize() - 1; +} + + + +////////////////////////////// +// +// Options::getArgumentCount -- Same as getArgCount(). +// + +int Options::getArgumentCount(void) { + return getArgCount(); +} + + + +////////////////////////////// +// +// Options::getBoolean -- returns true if the option was +// used on the command line. +// + +int Options::getBoolean(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return 0; + } + if (optionRegister[index]->getModifiedQ() == 1) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Options::getCommand -- returns argv[0] +// + +const char* Options::getCommand(void) { + if (argument.getSize() == 0) { + return ""; + } else { + return argument[0]; + } +} + + + +////////////////////////////// +// +// Options::getCommandLine -- returns a string which contains the +// command-line call to the program. +// + +const char* Options::getCommandLine(void) { + if (commandString != NULL) { + return commandString; + } + + int length = 0; + int i; + for (i=0; igetName()) == 0) { + return optionRegister[optionList[i]->getIndex()]->getDefinition(); + } + } + return (const char*)NULL; +} + + + +////////////////////////////// +// +// Options::getDouble -- returns the double float associated +// with the given option. Returns 0 if there is no +// number associated with the option. +// + +double Options::getDouble(const char* optionName) { + return strtod(getString(optionName), (char**)NULL); +} + + + +////////////////////////////// +// +// Options::getFlag -- +// + +char Options::getFlag(void) { + return optionFlag; +} + + + +////////////////////////////// +// +// Options::getFloat -- returns the floating point number +// associated with the given option. +// + +float Options::getFloat(const char* optionName) { + return (float)getDouble(optionName); +} + + + +////////////////////////////// +// +// Options::getInt -- returns the integer argument. Can handle +// hexadecimal, decimal, and octal written in standard +// C syntax. +// + +int Options::getInt(const char* optionName) { + return (int)strtol(getString(optionName), (char**)NULL, 0); +} + +int Options::getInteger(const char* optionName) { + return getInt(optionName); +} + + + +////////////////////////////// +// +// Options::getString -- +// + +const char* Options::getString(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return "UNKNOWN OPTION"; + } else { + return optionRegister[index]->getOption(); + } +} + + + +////////////////////////////// +// +// Options::optionsArg -- returns true if the --options is present +// on the command line, otherwise returns false. +// + +int Options::optionsArg(void) { + return optionsArgument; +} + + + +////////////////////////////// +// +// Options::print -- +// + +void Options::print(void) { + for (int i=0; igetDefinition() << std::endl; + } +} + + + +////////////////////////////// +// +// Options::reset -- +// + +void Options::reset(void) { + int i; + for (i=0; isetModified(aString); +} + + + + +////////////////////////////// +// +// setOptions -- +// + +void Options::setOptions(int argc, char** argv) { + processedQ = 0; + + gargc = argc; + gargv = argv; +} + + + +////////////////////////////// +// +// Options:getType -- returns the type of the option +// + +char Options::getType(const char* optionName) { + int index = getRegIndex(optionName); + if (index < 0) { + return -1; + } else { + return optionRegister[getRegIndex(optionName)]->getType(); + } +} + + + +////////////////////////////// +// +// Options::process -- same as verify +// default values: error_check = 1, suppress = 0; +// + +void Options::process(int argc, char** argv, int error_check, int suppress) { + setOptions(argc, argv); + verify(error_check, suppress); +} + + +void Options::process(int error_check, int suppress) { + verify(error_check, suppress); +} + + + +////////////////////////////// +// +// Options::verify -- +// default value: error_check = 1, suppress = 0; +// + +void Options::verify(int error_check, int suppress) { + options_error_check = error_check; + int gargp = 1; + int optionend = 0; + + if (suppress) { + suppressQ = 1; + } else { + suppressQ = 0; + } + + // if calling verify again, must remove previous argument list. + if (argument.getSize() != 0) { + for (int j=0; jgetIndex(); + } else if (strcmp("options", optionName) == 0) { + print(); + exit(1); + } + + if (options_error_check) { + std::cout << "Error: unknown option \"" << optionName << "\"." << std::endl; + print(); + exit(1); + } + + return -1; +} + + + +////////////////////////////// +// +// optionQ -- returns true if the string is an option +// "--" is not an option, also '-' is not an option. +// aString is assumed to not be NULL. +// + +int Options::optionQ(const char* aString, int& argp) { + if (aString[0] == getFlag()) { + if (aString[1] == '\0') { + argp++; + return 0; + } else if (aString[1] == getFlag()) { + if (aString[2] == '\0') { + argp++; + return 0; + } else { + return 1; + } + } else { + return 1; + } + } else { + return 0; + } +} + + + + +////////////////////////////// +// +// sortOptionNames -- +// + +void Options::sortOptionNames(void) { + qsort(optionList.getBase(), optionList.getSize(), + sizeof(option_list*), optionListCompare); + sortedQ = 1; +} + + + +////////////////////////////// +// +// storeOption -- +// + +#define OPTION_FORM_SHORT 0 +#define OPTION_FORM_LONG 1 +#define OPTION_FORM_CONTINUE 2 + +int Options::storeOption(int gargp, int& position, int& running) { + int optionForm; + char tempname[1024]; + char optionType = '\0'; + + if (running) { + optionForm = OPTION_FORM_CONTINUE; + } else if (gargv[gargp][1] == getFlag()) { + optionForm = OPTION_FORM_LONG; + } else { + optionForm = OPTION_FORM_SHORT; + } + + switch (optionForm) { + case OPTION_FORM_CONTINUE: + position++; + tempname[0] = gargv[gargp][position]; + tempname[1] = '\0'; + optionType = getType(tempname); + if (optionType != OPTION_BOOLEAN_TYPE) { + running = 0; + position++; + } + break; + case OPTION_FORM_SHORT: + position = 1; + tempname[0] = gargv[gargp][position]; + tempname[1] = '\0'; + optionType = getType(tempname); + if (optionType != OPTION_BOOLEAN_TYPE) { + position++; + } + break; + case OPTION_FORM_LONG: + position = 2; + while (gargv[gargp][position] != '=' && + gargv[gargp][position] != '\0') { + tempname[position-2] = gargv[gargp][position]; + position++; + } + tempname[position-2] = '\0'; + optionType = getType(tempname); + if (optionType == -1) { // suppressed --options option + optionsArgument = 1; + break; + } + if (gargv[gargp][position] == '=') { + if (optionType == OPTION_BOOLEAN_TYPE) { + std::cout << "Error: boolean variable cannot have any options: " + << tempname << std::endl; + exit(1); + } + position++; + } + break; + } + + if (optionType == -1) { // suppressed --options option + optionsArgument = 1; + gargp++; + position = 0; + return gargp; + } + + if (gargv[gargp][position] == '\0' && + optionType != OPTION_BOOLEAN_TYPE) { + gargp++; + position = 0; + } + + if (optionForm != OPTION_FORM_LONG && optionType == OPTION_BOOLEAN_TYPE && + gargv[gargp][position+1] != '\0') { + running = 1; + } else if (optionType == OPTION_BOOLEAN_TYPE && + gargv[gargp][position+1] == '\0') { + running = 0; + } + + if (gargp >= gargc) { + std::cout << "Error: last option requires a parameter" << std::endl; + exit(1); + } + setModified(tempname, &gargv[gargp][position]); + + if (!running) { + gargp++; + } + return gargp; +} + + +/////////////////////////////////////////////////////////////////////////// +// +// helping function +// + +////////////////////////////// +// +// optionListCompare -- for sorting the option list +// + +int optionListCompare(const void* a, const void* b) { +//cerr << " comparing: " << (*((option_list**)a))->getName() +// << " i=" << (*((option_list**)a))->getIndex() +// << " :to: " +// << (*((option_list**)b))->getName() +// << " i=" << (*((option_list**)b))->getIndex() << std::endl; + return strcmp((*((option_list**)a))->getName(), + (*((option_list**)b))->getName()); +} + + + +// md5sum: 63584ffabc92170fdb9ef5caedb5a3f6 - Options.cpp =css= 20030102 diff --git a/src/midiio/src/Options_private.cpp b/src/midiio/src/Options_private.cpp new file mode 100644 index 0000000..5a875a8 --- /dev/null +++ b/src/midiio/src/Options_private.cpp @@ -0,0 +1,358 @@ +// +// Copyright 1998-1999 by Craig Stuart Sapp, All Rights Reserved. +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Apr 5 13:07:18 PDT 1998 +// Last Modified: Sun Jan 10 05:43:24 PST 1999 +// Filename: ...sig/maint/code/sigBase/Options_private.cpp +// Web Address: http://sig.sapp.org/src/sigBase/Options_private.cpp +// Syntax: C++ +// +// Description: A private set of functions for use in the Options class. +// + +#include "Options_private.h" +#include +#include +#include + + +////////////////////////////// +// +// option_register::option_register -- +// + +option_register::option_register(void) { + definition = NULL; + defaultOption = NULL; + modifiedOption = NULL; + type = 's'; +} + + +option_register::option_register(const char* aDefinition, char aType, + const char* aDefaultOption, const char* aModifiedOption) { + definition = NULL; + defaultOption = NULL; + modifiedOption = NULL; + + setType(aType); + setDefinition(aDefinition); + setDefault(aDefaultOption); + setModified(aModifiedOption); +} + + + +////////////////////////////// +// +// option_register::~option_register -- +// + +option_register::~option_register() { + if (definition != NULL) { + delete [] definition; + } + definition = NULL; + + if (defaultOption != NULL) { + delete [] defaultOption; + } + defaultOption = NULL; + + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + modifiedOption = NULL; +} + + + +////////////////////////////// +// +// option_register::clearModified -- sets the modified string to +// NULL. +// + +void option_register::clearModified(void) { + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + modifiedOption = NULL; +} + + + +////////////////////////////// +// +// option_register::getDefinition -- returns the initial definition +// string used to define this entry. +// + +const char* option_register::getDefinition(void) { + return definition; +} + + + +////////////////////////////// +// +// option_register::getDefault -- returns the default string +// to be returned. Will never return a NULL; +// + +const char* option_register::getDefault(void) { + return defaultOption; +} + + + +////////////////////////////// +// +// option_register::getModified -- return the modified +// option string +// + +const char* option_register::getModified(void) { + return modifiedOption; +} + + + +////////////////////////////// +// +// option_register::getModifiedQ -- returns true if +// modified string is not null, false otherwise. +// + +int option_register::getModifiedQ(void) { + if (modifiedOption == NULL) { + return 0; + } else { + return 1; + } +} + + + +////////////////////////////// +// +// option_register::getType -- +// + +char option_register::getType(void) { + return type; +} + + + +////////////////////////////// +// +// option_register::getOption -- return the modified option +// or the default option if no modified option. +// + +const char* option_register::getOption(void) { + if (getModifiedQ()) { + return getModified(); + } else { + return getDefault(); + } +} + + + +////////////////////////////// +// +// option_register::reset -- deallocate space for all +// strings in object. (but default string is set to "") +// + +void option_register::reset(void) { + if (definition != NULL) { + delete [] definition; + } + definition = NULL; + + if (defaultOption != NULL) { + delete [] defaultOption; + } + defaultOption = NULL; + defaultOption = new char[1]; + defaultOption[0] = '\0'; + + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + modifiedOption = NULL; +} + + + +////////////////////////////// +// +// option_register::setDefault -- +// + +void option_register::setDefault(const char* aString) { + if (aString == NULL) { + std::cout << "Error: default string cannot be null" << std::endl; + exit(1); + } + + if (defaultOption != NULL) { + delete [] defaultOption; + } + if (aString == NULL) { + defaultOption = NULL; + } else { + defaultOption = new char[strlen(aString) + 1]; + strcpy(defaultOption, aString); + } +} + + + +////////////////////////////// +// +// option_register::setDefinition -- +// + +void option_register::setDefinition(const char* aString) { + + if (definition != NULL) { + delete [] definition; + } + if (aString == NULL) { + definition = NULL; + } else { + definition = new char[strlen(aString) + 1]; + strcpy(definition, aString); + } + +} + + + +////////////////////////////// +// +// option_register::setModified -- +// + +void option_register::setModified(const char* aString) { + if (modifiedOption != NULL) { + delete [] modifiedOption; + } + if (aString == NULL) { + modifiedOption = NULL; + } else { + modifiedOption = new char[strlen(aString) + 1]; + strcpy(modifiedOption, aString); + } +} + + + +////////////////////////////// +// +// option_register::setType -- +// + +void option_register::setType(char aType) { + type = aType; +} + + + +///////////////////////////////////////////////////////////////////////////// +/// option_list class definitions /////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + + +////////////////////////////// +// +// option_list::option_list -- +// + +option_list::option_list(void) { + name = NULL; + index = -1; +} + + + +////////////////////////////// +// +// option_list::option_list -- +// + +option_list::option_list(const char* optionName, int anIndex) { + name = NULL; + setIndex(anIndex); + setName(optionName); +} + + + +////////////////////////////// +// +// option_list::~option_list -- +// + +option_list::~option_list() { + if (name != NULL) { + delete [] name; + } + name = NULL; +} + + + +////////////////////////////// +// +// option_list::getIndex -- +// + +int option_list::getIndex(void) { + return index; +} + + + +////////////////////////////// +// +// option_list::getName -- +// + +const char* option_list::getName(void) { + return name; +} + + + +////////////////////////////// +// +// option_list::setName -- +// + +void option_list::setName(const char* aString) { + if (name != NULL) { + delete [] name; + } + name = new char[strlen(aString) + 1]; + strcpy(name, aString); +} + + + +////////////////////////////// +// +// option_list::setIndex -- +// + +void option_list::setIndex(int anIndex) { + index = anIndex; +} + + + +// md5sum: be3cc8ad0380820a9ea96739dc989657 - Options_private.cpp =css= 20030102 diff --git a/src/midiio/src/Sequencer_alsa.cpp b/src/midiio/src/Sequencer_alsa.cpp new file mode 100644 index 0000000..4c80e22 --- /dev/null +++ b/src/midiio/src/Sequencer_alsa.cpp @@ -0,0 +1,643 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Thu May 11 21:10:02 PDT 2000 +// Last Modified: Sat Oct 13 14:51:43 PDT 2001 (updated for ALSA 0.9 interface) +// Filename: ...sig/maint/code/control/Sequencer_alsa.cpp +// Web Address: http://sig.sapp.org/src/sig/Sequencer_alsa.cpp +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux ALSA raw midi devices. This class +// is inherited by the classes MidiInPort_alsa and +// MidiOutPort_alsa. +// + +#if defined(LINUX) && defined(ALSA) + +#include "Collection.h" +#include +#include +#include +#include +#include +#include +#include +#include /* for reading filename for MIDI info */ +#include "Sequencer_alsa.h" + +typedef unsigned char uchar; + +// define static variables: +int Sequencer_alsa::class_count = 0; +int Sequencer_alsa::initialized = 0; + +// static variables for MIDI I/O information database +int Sequencer_alsa::indevcount = 0; +int Sequencer_alsa::outdevcount = 0; + +Collection Sequencer_alsa::rawmidi_in; +Collection Sequencer_alsa::rawmidi_out; +Collection Sequencer_alsa::midiincard; +Collection Sequencer_alsa::midioutcard; +Collection Sequencer_alsa::midiindevice; +Collection Sequencer_alsa::midioutdevice; +Collection Sequencer_alsa::midiinname; +Collection Sequencer_alsa::midioutname; + + + +/////////////////////////////// +// +// Sequencer_alsa::Sequencer_alsa -- +// default value: autoOpen = 1; +// + +Sequencer_alsa::Sequencer_alsa(int autoOpen) { + if (class_count < 0) { + std::cerr << "Unusual class instantiation count: " << class_count << std::endl; + exit(1); + } else if (class_count == 0) { + buildInfoDatabase(); + } + + // will not autoOpen + + class_count++; +} + + + +////////////////////////////// +// +// Sequencer_alsa::~Sequencer_alsa -- +// + +Sequencer_alsa::~Sequencer_alsa() { + + if (class_count == 1) { + close(); + removeInfoDatabase(); + } else if (class_count <= 0) { + std::cerr << "Unusual class instantiation count: " << class_count << std::endl; + exit(1); + } + + class_count--; +} + + + +////////////////////////////// +// +// Sequencer_alsa::close -- close the sequencer device. The device +// automatically closes once the program ends. +// + +void Sequencer_alsa::close(void) { + int i; + + for (i=0; i= rawmidi_in.getSize()) { + return; + } + + if (rawmidi_in[index] != NULL) { + snd_rawmidi_close(rawmidi_in[index]); + rawmidi_in[index] = NULL; + } +} + + +void Sequencer_alsa::closeOutput(int index) { + if (index < 0 || index >= rawmidi_out.getSize()) { + return; + } + + if (rawmidi_out[index] != NULL) { + snd_rawmidi_close(rawmidi_out[index]); + rawmidi_out[index] = NULL; + } +} + + + +////////////////////////////// +// +// Sequencer_alsa::displayInputs -- display a list of the +// available MIDI input devices. +// default values: out = std::cout, initial = "\t" +// + +void Sequencer_alsa::displayInputs(std::ostream& out, char* initial) { + for (int i=0; i& cards, + Collection& devices) { + + cards.setSize(0); + devices.setSize(0); + cards.allowGrowth(1); + devices.allowGrowth(1); + + DIR* dir = opendir("/dev/snd"); + if (dir == NULL) { +// std::cout << "Error determining ALSA MIDI info: no directory called /dev/snd" +// << std::endl; +// exit(1); + } + + // read each file in the directory and store information if it is a MIDI dev + else { + int card; + int device; + struct dirent *dinfo; + dinfo = readdir(dir); + int count; + while (dinfo != NULL) { + if (strncmp(dinfo->d_name, "midi", 4) == 0) { + count = sscanf(dinfo->d_name, "midiC%dD%d", &card, &device); + if (count == 2) { + cards.append(card); + devices.append(device); + } + } + dinfo = readdir(dir); + } + + closedir(dir); + cards.allowGrowth(0); + devices.allowGrowth(0); + } +} + + +#endif /* LINUX and ALSA */ + +// md5sum: 8ccf0e750be06aeea90cdc8a7cc4499c - Sequencer_alsa.cpp =css= 20030102 diff --git a/src/midiio/src/Sequencer_alsa05.cpp b/src/midiio/src/Sequencer_alsa05.cpp new file mode 100644 index 0000000..ad4ef2d --- /dev/null +++ b/src/midiio/src/Sequencer_alsa05.cpp @@ -0,0 +1,518 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Thu May 11 21:10:02 PDT 2000 +// Last Modified: Wed Oct 3 22:18:27 PDT 2001 (frozen to ALSA 0.5) +// Filename: ...sig/maint/code/control/Sequencer_alsa05.cpp +// Web Address: http://sig.sapp.org/src/sig/Sequencer_alsa05.cpp +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux ALSA raw midi devices. This class +// is inherited by the classes MidiInPort_alsa05 and +// MidiOutPort_alsa05. +// + +#if defined(LINUX) && defined(ALSA05) + +#include "Collection.h" +#include +#include +#include +#include +#include +#include +#include +#include "Sequencer_alsa05.h" + +typedef unsigned char uchar; + +// define static variables: +int Sequencer_alsa05::class_count = 0; +int Sequencer_alsa05::initialized = 0; + +// static variables for MIDI I/O information database +int Sequencer_alsa05::indevcount = 0; +int Sequencer_alsa05::outdevcount = 0; + +Collection Sequencer_alsa05::rawmidi_in; +Collection Sequencer_alsa05::rawmidi_out; +Collection Sequencer_alsa05::midiincard; +Collection Sequencer_alsa05::midioutcard; +Collection Sequencer_alsa05::midiindevice; +Collection Sequencer_alsa05::midioutdevice; +Collection Sequencer_alsa05::midiinname; +Collection Sequencer_alsa05::midioutname; + + + +/////////////////////////////// +// +// Sequencer_alsa05::Sequencer_alsa05 -- +// default value: autoOpen = 1; +// + +Sequencer_alsa05::Sequencer_alsa05(int autoOpen) { + if (class_count < 0) { + cerr << "Unusual class instatiation count: " << class_count << endl; + exit(1); + } else if (class_count == 0) { + buildInfoDatabase(); + } + + if (autoOpen) { + open(); + } + + class_count++; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::~Sequencer_alsa05 -- +// + +Sequencer_alsa05::~Sequencer_alsa05() { + + if (class_count == 1) { + close(); + removeInfoDatabase(); + } else if (class_count <= 0) { + cerr << "Unusual class instatiation count: " << class_count << endl; + exit(1); + } + + class_count--; +} + + + +////////////////////////////// +// +// Sequencer_alsa05::close -- close the sequencer device. The device +// automatically closes once the program ends. +// + +void Sequencer_alsa05::close(void) { + int i; + + for (i=0; i +// Creation Date: Sun Jan 3 21:02:02 PST 1999 +// Last Modified: Fri Jan 8 04:50:05 PST 1999 +// Last Modified: Wed May 10 17:00:11 PDT 2000 (name change from _linux to _oss) +// Filename: ...sig/maint/code/control/MidiOutPort/Sequencer_oss.cpp +// Web Address: http://sig.sapp.org/src/sig/Sequencer_oss.cpp +// Syntax: C++ +// +// Description: Basic MIDI input/output functionality for the +// Linux OSS midi device /dev/sequencer. This class +// is inherited by the classes MidiInPort_oss and +// MidiOutPort_oss. +// + +#ifdef LINUX + +#include + + +#include +#include +#include +#include +#include +#include +#include "Sequencer_oss.h" + + +// define static variables: +const char* Sequencer_oss::sequencer = "/dev/sequencer"; +int Sequencer_oss::sequencer_fd = -1; +int Sequencer_oss::class_count = 0; +int Sequencer_oss::initialized = 0; +uchar Sequencer_oss::midi_write_packet[4] = {SEQ_MIDIPUTC, 0, 0, 0}; +uchar Sequencer_oss::midi_read_packet[4]; + + +// static variables for MIDI I/O information database +int Sequencer_oss::indevcount = 0; +int Sequencer_oss::outdevcount = 0; + +int* Sequencer_oss::indevnum = NULL; +int* Sequencer_oss::outdevnum = NULL; + +int* Sequencer_oss::indevtype = NULL; +int* Sequencer_oss::outdevtype = NULL; + +char** Sequencer_oss::indevnames = NULL; +char** Sequencer_oss::outdevnames = NULL; + + + +/////////////////////////////// +// +// Sequencer_oss::Sequencer_oss -- +// default value: autoOpen = 1; +// + +Sequencer_oss::Sequencer_oss(int autoOpen) { + if (autoOpen) { + open(); + } + + if (class_count < 0) { + std::cerr << "Unusual class instatiation count: " << class_count << std::endl; + exit(1); + } else if (class_count == 0) { + buildInfoDatabase(); + } + + class_count++; +} + + + +////////////////////////////// +// +// Sequencer_oss::~Sequencer_oss -- +// + +Sequencer_oss::~Sequencer_oss() { + class_count--; + + if (class_count == 0) { + close(); + removeInfoDatabase(); + } else if (class_count < 0) { + std::cerr << "Unusual class instatiation count: " << class_count << std::endl; + exit(1); + } +} + + + +////////////////////////////// +// +// Sequencer_oss::close -- close the sequencer device. The device +// automatically closes once the program ends, but you can close it +// so that other programs can use it. +// + +void Sequencer_oss::close(void) { + ::close(getFd()); +} + + + +////////////////////////////// +// +// Sequencer_oss::displayInputs -- display a list of the +// available MIDI input devices. +// default values: out = cout, initial = "\t" +// + +void Sequencer_oss::displayInputs(std::ostream& out, char* initial) { + for (int i=0; i= getNumInputs()) { + std::cerr << "Error: " << aDevice << " is greater than max in (" + << getNumInputs() << ")" << std::endl; + exit(1); + } + + return indevnames[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getNumInputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_oss::getNumInputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return indevcount; +} + + + +////////////////////////////// +// +// Sequencer_oss::getNumOutputs -- returns the total number of +// MIDI inputs that can be used. +// + +int Sequencer_oss::getNumOutputs(void) { + if (initialized == 0) { + buildInfoDatabase(); + } + return outdevcount; +} + + + +////////////////////////////// +// +// Sequencer_oss::getOutputName -- returns a string to the name of +// the specified output device. The string will remain valid as +// long as there are any sequencer devices in existence. +// + +const char* Sequencer_oss::getOutputName(int aDevice) { + if (initialized == 0) { + buildInfoDatabase(); + } + if (aDevice >= getNumOutputs()) { + std::cerr << "Error: " << aDevice << " is greater than max out (" + << getNumOutputs() << ")" << std::endl; + exit(1); + } + + return outdevnames[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::is_open -- returns true if the +// sequencer device is open, false otherwise. +// + +int Sequencer_oss::is_open(void) { + if (getFd() > 0) { + return 1; + } else { + return 0; + } +} + + + +///////////////////////////// +// +// Sequencer_oss::open -- returns true if the device +// was successfully opended (or already opened) +// + +int Sequencer_oss::open(void) { + if (getFd() <= 0) { + setFd(::open(sequencer, O_RDWR, 0)); + } + + return is_open(); +} + + + +////////////////////////////// +// +// Sequencer_oss::read -- reads MIDI bytes and also stores the +// device from which the byte was read from. Timing is not +// saved from the device. If needed, then it would have to +// be saved in this function, or just return the raw packet +// data (use rawread function). +// + +void Sequencer_oss::read(uchar* buf, uchar* dev, int count) { + int i = 0; + while (i < count) { + ::read(getFd(), midi_read_packet, sizeof(midi_read_packet)); + if (midi_read_packet[1] == SEQ_MIDIPUTC) { + buf[i] = midi_read_packet[1]; + dev[i] = midi_read_packet[2]; + i++; + } + } +} + + + +////////////////////////////// +// +// Sequencer_oss::rawread -- read Input MIDI packets. +// each packet contains 4 bytes. +// + +void Sequencer_oss::rawread(uchar* buf, int packetCount) { + ::read(getFd(), buf, packetCount * 4); +} + + + +////////////////////////////// +// +// Sequencer_oss::rebuildInfoDatabase -- rebuild the internal +// database that keeps track of the MIDI input and output devices. +// + +void Sequencer_oss::rebuildInfoDatabase(void) { + removeInfoDatabase(); + buildInfoDatabase(); +} + + + +/////////////////////////////// +// +// Sequencer_oss::write -- Send a byte out the specified MIDI +// port which can be either an internal or an external synthesizer. +// + +int Sequencer_oss::write(int device, int aByte) { + int status = 0; + + switch (getOutputType(device)) { + case MIDI_EXTERNAL: + midi_write_packet[1] = (uchar) (0xff & aByte); + midi_write_packet[2] = getOutDeviceValue(device); + status = ::write(getFd(), midi_write_packet,sizeof(midi_write_packet)); + break; + case MIDI_INTERNAL: + status = writeInternal(getOutDeviceValue(device), aByte); + break; + } + + if (status > 0) { + return 1; + } else { + return 0; + } + +} + + +int Sequencer_oss::write(int device, uchar* bytes, int count) { + int status = 1; + for (int i=0; i= getNumInputs()) { + std::cerr << "Error: " << aDevice << " is greater than max in (" + << getNumInputs() << ")" << std::endl; + exit(1); + } + + return indevnum[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getInputType -- returns 1 = external MIDI, +// 2 = internal MIDI +// + +int Sequencer_oss::getInputType(int aDevice) const { + if (aDevice >= getNumInputs()) { + std::cerr << "Error: " << aDevice << " is greater than max in (" + << getNumInputs() << ")" << std::endl; + exit(1); + } + + return indevtype[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getOutDeviceValue -- +// + +int Sequencer_oss::getOutDeviceValue(int aDevice) const { + if (aDevice >= getNumOutputs()) { + std::cerr << "Error: " << aDevice << " is greater than max out (" + << getNumOutputs() << ")" << std::endl; + exit(1); + } + + return outdevnum[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::getOutputType -- returns 1 = external MIDI, +// 2 = internal MIDI +// + +int Sequencer_oss::getOutputType(int aDevice) const { + if (aDevice >= getNumOutputs()) { + std::cerr << "Error: " << aDevice << " is greater than max out (" + << getNumOutputs() << ")" << std::endl; + exit(1); + } + + return outdevtype[aDevice]; +} + + + +////////////////////////////// +// +// Sequencer_oss::removeInfoDatabase -- +// + +void Sequencer_oss::removeInfoDatabase(void) { + initialized = 0; + + if (indevnum != NULL) delete [] indevnum; + if (outdevnum != NULL) delete [] outdevnum; + if (indevtype != NULL) delete [] indevtype; + if (outdevtype != NULL) delete [] outdevtype; + + int i; + if (indevnames != NULL) { + for (i=0; i 127) { + std::cerr << "Error: expecting MIDI data but got MIDI command: " + << aByte << std::endl; + exit(1); + } + + synth_message_buffer[synth_message_buffer_count++] = aByte; + } + + // check to see if the message is complete: + if (synth_message_bytes_expected == synth_message_buffer_count) { + status = transmitMessageToInternalSynth(); + synth_message_bytes_expected = 0; + synth_message_buffer_count = 0; + } + + return status; +} + + + +////////////////////////////// +// +// Sequencer_oss::transmitMessageToInternalSynth -- send the stored +// MIDI message to the internal synthesizer. +// + +int Sequencer_oss::transmitMessageToInternalSynth(void) { + int status; + switch (synth_message_buffer[0] & 0xf0) { + case 0x80: // Note-off + case 0x90: // Note-on + case 0xA0: // Aftertouch + status = transmitVoiceMessage(); + break; + case 0xB0: // Control change + case 0xC0: // Patch change + case 0xD0: // Channel pressure + case 0xE0: // Pitch wheel + status = transmitCommonMessage(); + break; + case 0xF0: + std::cerr << "Cannot handle 0xf0 commands yet" << std::endl; + exit(1); + break; + default: + std::cerr << "Error: unknown MIDI command" << std::endl; + exit(1); + } + + return status; +} + + + +////////////////////////////// +// +// Sequencer_oss::transmitVoiceMessage -- send a voice-type MIDI +// message to an internal synthesizer. +// + +int Sequencer_oss::transmitVoiceMessage(void) { + synth_write_message[0] = EV_CHN_VOICE; + synth_write_message[1] = synth_message_curr_device; + synth_write_message[2] = synth_message_buffer[0] & 0xf0; + synth_write_message[3] = synth_message_buffer[0] & 0x0f; + synth_write_message[4] = synth_message_buffer[1]; + synth_write_message[5] = synth_message_buffer[2]; + synth_write_message[6] = 0; + synth_write_message[7] = 0; + + int status; + status = ::write(getFd(), synth_write_message, sizeof(synth_write_message)); + + if (status > 0) { + return 1; + } else { + return 0; + } +} + + + +////////////////////////////// +// +// Sequencer_oss::transmitCommonMessage -- send a common-type MIDI +// message to an internal synthesizer. +// + +int Sequencer_oss::transmitCommonMessage(void) { + synth_write_message[0] = EV_CHN_COMMON; + synth_write_message[1] = synth_message_curr_device; + synth_write_message[2] = synth_message_buffer[0] & 0xf0; + synth_write_message[3] = synth_message_buffer[0] & 0x0f; + + switch (synth_write_message[2]) { + case 0xB0: // Control change + synth_write_message[4] = synth_message_buffer[1]; + synth_write_message[5] = 0; + synth_write_message[6] = synth_message_buffer[2]; + synth_write_message[7] = 0; + break; + case 0xC0: // Patch change + case 0xD0: // Channel pressure + synth_write_message[4] = synth_message_buffer[1]; + synth_write_message[5] = 0; + synth_write_message[6] = 0; + synth_write_message[7] = 0; + break; + case 0xE0: // Pitch wheel + synth_write_message[4] = 0; + synth_write_message[5] = 0; + synth_write_message[6] = synth_message_buffer[1]; + synth_write_message[7] = synth_message_buffer[2]; + break; + default: + std::cerr << "Unknown Common MIDI message" << std::endl; + exit(1); + } + + int status; + status = ::write(getFd(), synth_write_message, sizeof(synth_write_message)); + + if (status > 0) { + return 1; + } else { + return 0; + } +} + + + +#endif // LINUX +// md5sum: bc7b96041137b22f3d3c35376b5912c6 - Sequencer_oss.cpp =css= 20030102 diff --git a/src/midiio/src/SigTimer.cpp b/src/midiio/src/SigTimer.cpp new file mode 100644 index 0000000..5786098 --- /dev/null +++ b/src/midiio/src/SigTimer.cpp @@ -0,0 +1,498 @@ +// +// Programmer: Craig Stuart Sapp +// Thanks to: Erik Neuenschwander +// for Windows 95 assembly code for Pentium clock cycles. +// Ozgur Izmirli +// for concept of periodic timer. +// Creation Date: Mon Oct 13 11:34:57 GMT-0800 1997 +// Last Modified: Tue Feb 10 21:05:19 GMT-0800 1998 +// Last Modified: Sat Sep 19 15:56:48 PDT 1998 +// Last Modified: Mon Feb 22 04:44:25 PST 1999 +// Last Modified: Sun Nov 28 12:39:39 PST 1999 (added adjustPeriod()) +// Filename: .../sig/code/control/SigTimer/SigTimer.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/SigTimer.cpp +// Syntax: C++ +// +// Description: This class can only be used on Motorola Pentinum 75 Mhz +// chips or better because the timing information is +// extracted from the clock cycle count from a register +// on the CPU itself. This class will estimate the +// speed of the computer, but it would be better if there +// was a way of finding out the speed from some function. +// This class is used primarily for timing of MIDI input +// and output at a millisecond resolution. +// + + +#include "SigTimer.h" +#include +#include + + +// get Sleep or usleep function definition for measureCpu function: +#ifdef VISUAL + #define WIN32_LEAN_AND_MEAN + #include + #undef WIN32_LEAN_AND_MEAN +#else + #include +#endif + + +// declare static variables +int64bits SigTimer::globalOffset = 0; +int SigTimer::cpuSpeed = 0; // in cycles per second + + + +////////////////////////////// +// +// SigTimer::SigTimer +// + +SigTimer::SigTimer(void) { + if (globalOffset == 0) { // coordinate offset between timers + globalOffset = clockCycles(); + } + if (cpuSpeed <= 0) { // initialize CPU speed value + cpuSpeed = measureCpuSpeed(1); + if (cpuSpeed <= 0) { + cpuSpeed = 100000000; + } + } + + offset = globalOffset; // initialize the start time of timer + ticksPerSecond = 1000; // default of 1000 ticks per second + period = 1000.0; // default period of once per second +} + + +SigTimer::SigTimer(int aSpeed) { + if (globalOffset == 0) { + globalOffset = clockCycles(); + } + cpuSpeed = aSpeed; + + offset = globalOffset; + ticksPerSecond = 1000; + period = 1000.0; // default period of once per second +} + + +SigTimer::SigTimer(SigTimer& aTimer) { + offset = aTimer.offset; + ticksPerSecond = aTimer.ticksPerSecond; + period = aTimer.period; +} + + + +////////////////////////////// +// +// SigTimer::~SigTimer +// + +SigTimer::~SigTimer() { + // do nothing +} + + + +////////////////////////////// +// +// SigTimer::adjustPeriod -- adjust the period of the timer. +// + +void SigTimer::adjustPeriod(double periodDelta) { + offset -= (int64bits)(getCpuSpeed() * getPeriod() * periodDelta / + getTicksPerSecond()); +} + + + +////////////////////////////// +// +// SigTimer::clockCycles -- returns the number of clock cycles since last reboot +// HARDWARE DEPENDENT -- currently for Pentiums only. +// static function. +// + + +int64bits SigTimer::clockCycles() { +#ifndef VISUAL + int64bits output; + + // For Pentiums, you can get the number of clock cycles elapsed + // since the last reboot with the following assembler code: + __asm__ volatile (".byte 0x0f, 0x31" : "=A" (output)); + +#else + int64bits output; + unsigned long high_end, low_end; + __asm { + __asm _emit 0x0f __asm _emit 0x31 + mov high_end, edx + mov low_end, eax + } + output = high_end; + output = output << 32; + output += low_end; +#endif + + return output; +} + + + +////////////////////////////// +// +// SigTimer::expired -- returns the integral number of periods +// That have passed since the last update or reset. +// See getPeriodCount which returns a floating point +// count of the period position. +// + + +int SigTimer::expired(void) const { + return (int)(getTime()/period); +} + + + +////////////////////////////// +// +// SigTimer::getCpuSpeed -- returns the CPU speed of the computer. +// (static function) +// + +int SigTimer::getCpuSpeed(void) { + return cpuSpeed; +} + + + +////////////////////////////// +// +// SigTimer::getPeriod -- returns the timing period of the timer, +// if the timer is being used as a periodic timer. +// + +double SigTimer::getPeriod(void) const { + return period; +} + + + +////////////////////////////// +// +// SigTimer::getPeriodCount -- returns the current period count +// of the timer as a double. Similar in behavior to expired +// function but lists the current fraction of a period. +// + +double SigTimer::getPeriodCount(void) const { + return (double)getTime()/period; +} + + + +////////////////////////////// +// +// SigTimer::getTempo -- returns the current tempo in terms +// of beats (ticks) per minute. +// + +double SigTimer::getTempo(void) const { + return getTicksPerSecond() * 60.0 / getPeriod(); +} + + + +////////////////////////////// +// +// SigTimer::getTicksPerSecond -- return the number of ticks per +// second. +// + +int SigTimer::getTicksPerSecond(void) const { + return ticksPerSecond; +} + + + +////////////////////////////// +// +// SigTimer::getTime -- returns time in milliseconds by default. +// time can be altered to be in some other unit of time +// by using the setTicksPerSecond function. +// (Default is 1000 ticks per second.) +// + +int SigTimer::getTime(void) const { + return (int)((clockCycles()-offset)/getFactor()); +} + + + +////////////////////////////// +// +// SigTimer::getTimeInSeconds +// + +double SigTimer::getTimeInSeconds(void) const { + return ((clockCycles()-offset)/(double)cpuSpeed); +} + + + +////////////////////////////// +// +// SigTimer::getTimeInTicks +// + +int SigTimer::getTimeInTicks(void) const { + return (int)((clockCycles()-offset)/getFactor()); +} + + + +////////////////////////////// +// +// SigTimer::measureCpuSpeed -- returns the number of clock cycles in +// one second. Accuracy to about +/- 5%. +// default value: quantize = 0. +// + +int SigTimer::measureCpuSpeed(int quantize) { + int64bits a, b; + a = clockCycles(); + #ifdef VISUAL + Sleep(1000/4); + #else + usleep(1000000/4); + #endif + b = clockCycles(); + + int output = (int)(4*(b-a-140100-450000)); + + if (quantize) { + // quantize to a known computer CPU speed + if (output < 78000000) { + output = 75000000; + } else if (output < 95000000) { + output = 90000000; + } else if (output < 110000000) { + output = 100000000; + } else if (output < 140000000) { + output = 133000000; + } else if (output < 155000000) { + output = 150000000; + } else if (output < 180000000) { + output = 166000000; + } else if (output < 215000000) { + output = 200000000; + } else if (output < 250000000) { + output = 233000000; + } else if (output < 280000000) { + output = 266000000; + } else if (output < 325000000) { + output = 300000000; + } else if (output < 375000000) { + output = 350000000; + } else if (output < 425000000) { + output = 400000000; + } else { + output = output; + } + } // end if quantize + + return output; +} + + + +////////////////////////////// +// +// SigTimer::reset -- set the timer to 0. +// + +void SigTimer::reset(void) { + offset = clockCycles(); +} + + + +////////////////////////////// +// +// SigTimer::setCpuSpeed -- You can also vary the CPU speed here to cause the +// getTime function to output different units of time, but the +// setTicksPerSecond is a more appropriate place to do such a thing. +// + +void SigTimer::setCpuSpeed(int aSpeed) { + if (aSpeed <= 0) { + std::cerr << "Error: Cannot set the cpu speed to be negative: " + << aSpeed << std::endl; + exit(1); + } + cpuSpeed = aSpeed; +} + + + +////////////////////////////// +// +// SigTimer::setPeriod -- sets the period length of the timer. +// input value cannot be less than 1.0. +// + +void SigTimer::setPeriod(double aPeriod) { + if (aPeriod < 1.0) { + std::cerr << "Error: period too small: " << aPeriod << std::endl; + exit(1); + } + period = aPeriod; +} + + + +////////////////////////////// +// +// SigTimer::setPeriodCount -- adjusts the offset time according +// to the current period to match the specified period count. +// + +void SigTimer::setPeriodCount(double aCount) { + offset = (int64bits)(clockCycles() - aCount * getPeriod() * + getCpuSpeed() / getTicksPerSecond()); +} + + + +////////////////////////////// +// +// SigTimer::setTempo -- sets the period length in terms of +// beats per minute. +// + +void SigTimer::setTempo(double beatsPerMinute) { + if (beatsPerMinute < 1.0) { + std::cerr << "Error: tempo is too slow: " << beatsPerMinute << std::endl; + exit(1); + } + double count = getPeriodCount(); + period = getTicksPerSecond() * 60.0 / beatsPerMinute; + setPeriodCount(count); +} + + + +////////////////////////////// +// +// SigTimer::setTicksPerSecond +// + +void SigTimer::setTicksPerSecond(int aTickRate) { + if (aTickRate <= 0) { + std::cerr << "Error: Cannot set the tick rate to be negative: " + << aTickRate << std::endl; + exit(1); + } + ticksPerSecond = aTickRate; +} + + + +////////////////////////////// +// +// SigTimer::start +// + +void SigTimer::start(void) { + reset(); +} + + + +////////////////////////////// +// +// SigTimer::sync +// + +void SigTimer::sync(SigTimer& aTimer) { + offset = aTimer.offset; +} + + + +////////////////////////////// +// +// SigTimer::update -- set the timer start to the next period. +// + +void SigTimer::update(void) { + if (getTime() >= getPeriod()) { + offset += (int64bits)(getPeriod() * getFactor()); + } +} + + +// update(int) will do nothing if the periodCount is greater than +// than the expired period count + +void SigTimer::update(int periodCount) { + if (periodCount > expired()) { + return; + } else { + offset += (int64bits)(getPeriod() * getFactor() * periodCount); + } +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// protected functions: +// + + +////////////////////////////// +// +// SigTimer::getFactor -- +// + +double SigTimer::getFactor(void) const { + return (double)((double)getCpuSpeed()/(double)getTicksPerSecond()); +} + + + +/////////////////////////////////////////////////////////////////////////// +// +// Miscellaneous timing functions are located here untill a better +// place can be found: +// + +void millisleep(int milliseconds) { + #ifdef VISUAL + Sleep(milliseconds); + #else + usleep( milliseconds * 1000); + #endif +} + + +void millisleep(float milliseconds) { + #ifdef VISUAL + // cannot convert to microseconds in Visual C++ yet. + // Tell me how and I'll fix the following line + Sleep((unsigned long)milliseconds); + #else + usleep((int)(milliseconds * 1000.0)); + #endif +} + + + + +// md5sum: b35e9e6a8d6fd16636d7fca5d565f284 - SigTimer.cpp =css= 20030102 diff --git a/src/midiio/src/Voice.cpp b/src/midiio/src/Voice.cpp new file mode 100644 index 0000000..ed05bce --- /dev/null +++ b/src/midiio/src/Voice.cpp @@ -0,0 +1,334 @@ +// +// Programmer: Craig Stuart Sapp +// Creation Date: Sun Oct 11 18:39:14 PDT 1998 +// Last Modified: Sun Oct 11 18:39:18 PDT 1998 +// Filename: ...sig/maint/code/control/Voice/Voice.cpp +// Web Address: http://www-ccrma.stanford.edu/~craig/improv/src/Voice.cpp +// Syntax: C++ +// +// Description: The Voice class is a MIDI output class which keeps +// track of the last note played in to it. If the last +// note was not turned off when a new note is played, +// then the old note will be turned off before the +// new note is played. +// + +#include "Voice.h" + + +// declare static variables: +SigTimer Voice::timer; + +////////////////////////////// +// +// Voice::Voice +// + +Voice::Voice(int aChannel) { + chan = oldChan = aChannel; + vel = oldVel = key = oldKey = 0; +} + + +Voice::Voice(const Voice& aVoice) { + chan = aVoice.chan; + vel = aVoice.vel; + key = aVoice.key; + oldChan = 0; + oldVel = 0; + oldKey = 0; +} + + +Voice::Voice(void) { + chan = oldChan = key = oldKey = vel = oldVel = 0; +} + + +////////////////////////////// +// +// Voice::~Voice +// + +Voice::~Voice() { + off(); +} + + + +////////////////////////////// +// +// Voice::cont -- use default channel if none specified for +// the continuous controller message. +// + +void Voice::cont(int controller, int data) { + MidiOutput::cont(getChannel(), controller, data); +} + + + +////////////////////////////// +// +// Voice::getChan -- returns the channel of the voice. +// Synonym for getChannel. +// + +int Voice::getChan(void) const { + return chan; +} + + + +////////////////////////////// +// +// Voice::getChannel -- returs the channel of the voice. +// + +int Voice::getChannel(void) const { + return chan; +} + + + +////////////////////////////// +// +// Voice::getKey -- returns the current MIDI key number of the voice. +// Synonym for getKeynum. +// + +int Voice::getKey(void) const { + return key; +} + + + +////////////////////////////// +// +// Voice::getKeynum -- returns the current MIDI key number of the voice. +// + +int Voice::getKeynum(void) const { + return key; +} + + +////////////////////////////// +// +// Voice::getOffTime -- returns the last note off message sent +// out of the voice object +// + +int Voice::getOffTime(void) const { + return offTime; +} + + + +////////////////////////////// +// +// Voice::getOnTime -- returns the last note on message sent +// out of the voice object. +// + +int Voice::getOnTime(void) const { + return onTime; +} + + + +////////////////////////////// +// +// Voice::getVel -- returns the current velocity of the MIDI key. +// Synonym for getVelocity. +// + +int Voice::getVel(void) const { + return vel; +} + + + +////////////////////////////// +// +// Voice::getVelocity -- returns the current velocity of the MIDI key. +// + +int Voice::getVelocity(void) const { + return vel; +} + + + +////////////////////////////// +// +// Voice::off +// + +void Voice::off(void) { + if (status() != 0) { + offTime = timer.getTime(); + MidiOutput::play(oldChan, oldKey, 0); + oldVel = 0; + } +} + + + +////////////////////////////// +// +// Voice::pc -- use default channel if none is specified +// + +void Voice::pc(int aTimbre) { + MidiOutput::pc(getChannel(), aTimbre); +} + + + +////////////////////////////// +// +// Voice::play +// + +void Voice::play(int aChannel, int aKeyno, int aVelocity) { + off(); + MidiOutput::play(aChannel, aKeyno, aVelocity); + oldChan = aChannel; + oldKey = aKeyno; + oldVel = aVelocity; + setChannel(aChannel); + setKeynum(aKeyno); + setVelocity(aVelocity); + + if (aVelocity != 0) { + onTime = timer.getTime(); + } else { + offTime = timer.getTime(); + } +} + + +void Voice::play(int aKeyno, int aVelocity) { + off(); + MidiOutput::play(getChannel(), aKeyno, aVelocity); + oldChan = getChannel(); + oldKey = aKeyno; + oldVel = aVelocity; + setKeynum(aKeyno); + setVelocity(aVelocity); + + if (aVelocity != 0) { + onTime = timer.getTime(); + } else { + offTime = timer.getTime(); + } +} + + +void Voice::play(void) { + off(); + MidiOutput::play(getChannel(), getKey(), getVel()); + oldChan = getChannel(); + oldKey = getKey(); + oldVel = getVel(); + + if (getVel() != 0) { + onTime = timer.getTime(); + } else { + offTime = timer.getTime(); + } +} + + + +////////////////////////////// +// +// Voice::setChan -- set the MIDI channel. Synonym for setChannel. +// + +void Voice::setChan(int aChannel) { + chan = aChannel; +} + + + +////////////////////////////// +// +// Voice::setChannel -- set the MIDI channel of the voice. +// + +void Voice::setChannel(int aChannel) { + chan = aChannel; +} + + + +////////////////////////////// +// +// Voice::setKey -- set the keynumber of the voice +// Synonym for setKeyno. +// + +void Voice::setKey(int aKeynum) { + key = aKeynum; +} + + + +////////////////////////////// +// +// Voice::setKeynum -- set the keynumber of the voice +// + +void Voice::setKeynum(int aKeynum) { + key = aKeynum; +} + + + +////////////////////////////// +// +// Voice::setVel -- set the MIDI velocity of the voice. +// Synonym for setVelocity. +// + +void Voice::setVel(int aVelocity) { + vel = aVelocity; +} + + + +////////////////////////////// +// +// Voice::setVelocity +// + +void Voice::setVelocity(int aVelocity) { + vel = aVelocity; +} + + + +////////////////////////////// +// +// Voice::status -- returns zero if off or positive if on. +// + +int Voice::status(void) const { + return oldVel; +} + + + +////////////////////////////// +// +// Voice::sustain -- uses default channel if none specified. +// + +void Voice::sustain(int aStatus) { + MidiOutput::sustain(getChannel(), aStatus); +} + + +// md5sum: d02ca41ae3b4e07efe7fedc720e52573 - Voice.cpp =css= 20030102 -- cgit v1.2.1