hexter-1.0.2/ 0000755 0000764 0000764 00000000000 12046775671 010041 5 0000000 0000000 hexter-1.0.2/README 0000644 0000764 0000764 00000064062 12044525703 010634 0000000 0000000 hexter
======
A Yamaha DX7 modeling software synthesizer
for the DSSI Soft Synth Interface
Introduction
============
hexter is a software synthesizer that models the sound generation of
a Yamaha DX7 synthesizer. It can easily load most DX7 patch bank
files, edit those patches via a built-in editor or MIDI sys-ex
messages (ALSA systems only), and recreate the sound of the DX7 with
greater accuracy than any previous open-source emulation (that the
author is aware of....)
hexter operates as a plugin for the DSSI Soft Synth Interface. DSSI
is a plugin API for software instruments (soft synths) with user
interfaces, permitting them to be hosted in-process by audio
applications. More information on DSSI can be found at:
http://dssi.sourceforge.net/
hexter is written and copyright (c) 2012 by Sean Bolton, and
licensed under the GNU General Public License, version 2 or later.
See the enclosed file COPYING for details. While this software is
'free' within the requirements of this license, I (Sean) would
appreciate any or all of the following should you find hexter
useful:
- an email stating where you're from and how you're using
hexter, sent to .
- copies of or links to music you've created with hexter.
- any favorite patches you create for hexter, or any patches
that work on a real DX7 but not on hexter.
- suggestions for improving hexter.
hexter is indirectly the result of cumulative effort by a large
number of contributors, see the AUTHORS file for details.
Requirements
============
hexter requires the following:
- DSSI version 0.4 or greater, available from the
dssi.sourceforge.net address above.
- liblo version 0.12 or greater (0.23 or greater recommended), a
library implementing the Open Sound Control (OSC) protocol,
available at:
http://liblo.sourceforge.net/
- pkgconfig with PKG_CONFIG_PATH set appropriately to pick up
DSSI and liblo.
- GTK+ version 2.4 or later.
- the LADSPA v1.x SDK.
- the ALSA headers (DSSI plugins use ALSA structures, but not
the actual drivers, so you don't necessarily need the
drivers installed.) Users of non-ALSA systems may use
libdssialsacompat, available at:
http://smbolton.com/linux.html
- a working DSSI host. hexter has been tested with the
jack-dssi-host, available in the DSSI distribution, and with
ghostess, available at:
http://smbolton.com/linux.html
- automake 1.7 and autoconf 2.57 or better if you wish to
recreate the build files.
Installation
============
The generic installation instructions in the enclosed file INSTALL
aren't particularly helpful, so try this instead:
1. Unpack the tar file.
2. Make sure PKG_CONFIG_PATH is set correctly to locate the
dssi.pc and liblo.pc pkgconfig files. On many systems, this
will be:
$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ export PKG_CONFIG_PATH
3. 'cd' into the package directory and execute './configure'.
configure will add '-Wall' and my favorite optimizations to
CFLAGS for you if you don't include any '-Wall' or '-O' options.
If you're using gcc and wish to provide your own optimization
flags, you MUST at least use '-finline' and a non-zero '-O' flag
to get decent results.
Depending on your hardware, you may wish to add the
'--enable-floating-point' option to the configure cammand line.
See the 'Fixed Point vs. Floating Point Rendering' section
below. (If you're not sure, it is safest to leave it off.)
4. Enable debugging information if you desire: edit the file
src/hexter.h, and define DSSP_DEBUG as explained in the
comments.
5. Do 'make'. Hopefully it should build without warnings (or
errors.)
6. 'make install' will install the following:
/lib/dssi/hexter/hexter_gtk
/lib/dssi/hexter.so
/lib/dssi/hexter.la
/share/hexter/dx7_roms.dx7
/share/hexter/fb01_roms_converted_12.dx7
/share/hexter/fb01_roms_converted_34.dx7
/share/hexter/fb01_roms_converted_5.dx7
/share/hexter/tx7_roms.dx7
Feedback on your experiences building hexter is appreciated.
Operation
=========
To run the hexter plugin under the jack-dssi-host provided
in the DSSI distribution, I do the following:
1. Start JACK.
2. Start jack-dssi-host, supplying the correct plugin path
and filename (substitute as appropriate):
$ DSSI_PATH=/lib/dssi sudo jack-dssi-host hexter.so
jack-dssi-host should start, and moments later the hexter
graphic user interface should appear.
3. Use qjackctl or aconnect to connect jack-dssi-host to a MIDI
source, such as vkeybd.
4. Begin playing sounds! If you get no response, try clicking the
'Send Test Note' button in the hexter GUI. This sends a note
directly via the host to the plugin, so if you hear sound now,
look for a problem between the host and your MIDI source. If
you still don't hear sound, I'd look for a problem between the
host and your output device. If you continue having trouble,
you might recompile with DSSP_DEBUG bit 2 set, which will cause
the plugin to continuously output a quiet buzz to help debug
your outgoing signal path.
hexter starts up with a default set of sound presets, or 'patches',
that you can select either by selecting the GUI 'Patches' tab and
clicking on the patch name, or by sending a MIDI program change from
your MIDI source with the appropriate program number.
Patch Import/Export
===================
hexter can import DX7 patch bank files in several formats:
- The standard 32-voice bulk dump sys-ex format. These are 4104
bytes long, and you can find a million of them by Googling for "dx7
patches". hexter places no restrictions on their filenames.
- The standard single-voice (edit buffer) sys-ex format. These are
163 bytes long.
- Raw packed patch data. These are 128 bytes per patch, and may
contain any number of patches (although hexter can only load up to
128 of them.) Note, though, that if the file is 8192 bytes long and
has any of the filename suffixes ".tx7", ".TX7", ".snd", or ".SND",
the second half of the file will be ignored (Dr. T and Steinberg TX7
formats).
- Standard MIDI files containing either a 32-voice bulk dump sys-ex
message or a single voice dump sys-ex message. If the file contains
more than one qualifying sys-ex message, only the first will be used.
- Two concatenated 32-voice bulk dump sys-ex messages (8208 bytes
long.)
- Steinberg Synthworks format (5216 bytes long).
- Transform XSyn format (8192 bytes long).
- Voyetra SIDEMAN DX/TX and Patchmaster DX7/TX7 formats (9816
or 5663 bytes long).
- Yamaha DX200 editor format (326454 bytes long).
You may use the "Import Patch Bank..." option in the File menu to
import patches. After selecting the filename, you will need to
specify the program number (0 to 127) at which to begin importing
the patches.
Several patch bank files are installed with hexter in
/share/hexter/.
You may also export patch banks using the File menu "Export Patch
Bank..." option. You can then select which of the formats to save
in, and what range of patches to export. Finally, select the
filename to which you want to save, and click 'Ok'.
Synthesizer Configuration
=========================
On the 'Configuration' tab of the hexter GUI, there are a number of
controls for configuring hexter:
- tuning: sets the tuning of this instance of the plugin,
as Hz for A-above-middle-C.
- volume: adjusts the output volume for this instance, from -70dB to
+20dB relative to a nominal reference level (-18.1dB per voice,
which permits approximately 8 voice polyphony within -1.0 to
+1.0 float.)
- polyphony (instance): Sets the maximum polyphony for this instance
of the plugin. If you attempt to play more notes than this
setting, already-playing notes will be killed so that newer
notes can be played.
- polyphony (global): Sets the maximum polyphony for all hexter
instances running on this host. If you are getting xruns, try
reducing this setting.
- monophonic modes: sets poly/mono operation for this instance of
the plugin to one of the following:
'Off' - polyphonic operation.
'On' - monophonic operation, where the envelopes are
retriggered upon each incoming note on event.
'Once' - monophonic operation, where the envelopes are triggered
only on the first note on of a legato phrase -- that
is, if you hold one note while playing a second, the
envelopes will not be retriggered for the second note.
'Both' - monophonic operation, where the envelopes are
retriggered at each note on, and upon note off when
other keys are still held.
- disable LFO/Mod/Perf (0.5.x compatibility): selecting this check
box will disable the LFO, amplitude modulation, pitch
modulation, and performance parameter enhancements provided by
hexter 0.6.0 and later versions, forcing it to sound just like
the 0.5.9 version. This is provided for backward compatibility
with existing projects that used hexter 0.5.9.
- Sys-Ex Patch Editing: On ALSA systems, hexter has the ability to
receive MIDI system exclusive messages from an external patch
editor/librarian. Any patch edits received are reflected in
hexter's built-in patch editor, and must be saved using the
built-in editor's 'Save Changes into Patch Bank' button (see
below).
Sys-ex patch editing is enabled on the 'Configuration' tab by
depressing the 'Enable Sys-Ex Editing' button. The hexter GUI
then creates an ALSA MIDI client and displays its client and
port number in the status window below the 'Sys-Ex Receive
Channel' slider. Set the channel appropriately and route your
external patch editor to this port using aconnect or similar,
and the hexter instance will be ready to receive patch edits.
Note that hexter only _receives_ MIDI sys-ex messages, and does
not send them. Also, it only receives single patch dumps and
voice parameter changes, so any 'get patch data from synth' or
'send 32 voices to synth' functions of your librarian will not
work.
Performance Parameters
======================
The 'Performance' tab of the hexter GUI contains controls for the
DX7/TX7 Performance Parameters:
- pitch bend range: sets the response to MIDI pitch bend messages,
in semitones.
- portamento time: sets the portamento time. Note that as of
version 0.6.1, the portamento code is still unfinished.
- mod wheel sensitivity: sets the depth of response to MIDI
modulation wheel control change messages (MIDI control change 1).
- mod wheel assign: these three check boxes set which destinations
the modulation wheel affects: selecting 'P' routes the LFO to
pitch modulation (vibrato), 'A' routes the LFO to amplitude
modulation (tremelo or wah), and 'E' routes the modulation wheel
value itself to amplitude modulation.
- foot sensitivity, foot assign, pressure sens., pressure assign,
breath sens., and breath assign: these set the sensitivity and
routing as described above for the foot controller (MIDI CC 4),
for pressure (both channel and key pressure), and for the breath
controller (CC 2), respectively.
Patch Editing
=============
The current patch may be edited by selecting 'Edit Patch...' from
the 'Edit' menu, which opens the patch editor window. All patch
edits accumulate as a temporary 'overlay' replacing the current
patch, but are not saved into the patch bank until you click the
'Save Changes into Patch Bank' button and complete the save process.
(Once you've saved edits into the patch bank, remember to save the
bank to disk using the 'Export Patch Bank...' option of the 'File'
menu!)
Clicking the 'Discard Changes' button or selecting another patch
from the 'Patches' tab will discard any active edits. At any time
the top status line of the editor window will tell you which patch
is being edited, and whether there are any changes in effect.
The editor has two modes of operation, selected by the 'Editor Mode'
combo box near the bottom left of the editor window. One mode,
called 'Widgy', uses standard GTK+ widgets for editing patch
parameters, and displays graphical representations of envelopes and
scaling curves to aid in comprehension of the patch parameters. The
other mode, called 'Retro' is based on text-based editors of decades
past. You may switch between editor modes at any time.
While the 'Retro' mode provides little in terms of visualization
assistance, it can provide the experienced user with more efficient
editing. Both the mouse and cursor keys may be used to select the
parameter to be edited. Generally, the number keys are used to enter
a parameter directly, the '-' key decrements a parameter, the '+' or
'=' keys increment the parameter, and the 'delete' or 'backspace'
key will reset the parameter to a default value. Perhaps most
convient for users without a separate MIDI keyboard, the space bar
can be used to toggle a test note, even while changing patches with
other keys!
MIDI Controller Mapping
=======================
In addition to the performance parameter MIDI messages mentioned
above, hexter responds to MIDI volume (MIDI control change 39),
sustain pedal (MIDI CC 64), and all-sounds-off, all-notes-off, and
reset-controllers control messages (CCs 120, 123, and 121,
respectively).
The operator parameters of the current patch can also be changed via
the following MIDI control change (CC) and non-registered parameter
(NRPN) messages. Messages marked with '*' in the 'Operator' column
will cause an immediate effect on playing notes, while the others
will only affect subsequently-played notes.
CC or NRPN | Operator | Parameter
-------------------------------+----------+------------------------
CC 16 (General Purpose #1 MSB) | * 1 | Frequency Coarse
CC 17 (General Purpose #2 MSB) | * 2 | Frequency Coarse
CC 18 (General Purpose #3 MSB) | * 3 | Frequency Coarse
CC 19 (General Purpose #4 MSB) | * 4 | Frequency Coarse
CC 80 (General Purpose #5) | * 5 | Frequency Coarse
CC 81 (General Purpose #6) | * 6 | Frequency Coarse
NRPN 0 | 6 | Envelope Generator Rate 1
NRPN 1 | 6 | Envelope Generator Rate 2
NRPN 2 | 6 | Envelope Generator Rate 3
NRPN 3 | 6 | Envelope Generator Rate 4
NRPN 4 | 6 | Envelope Generator Level 1
NRPN 5 | 6 | Envelope Generator Level 2
NRPN 6 | 6 | Envelope Generator Level 3
NRPN 7 | 6 | Envelope Generator Level 4
NRPN 8 | 6 | Keyboard Level Scaling Break Point
NRPN 9 | 6 | Keyboard Level Scaling Left Depth
NRPN 10 | 6 | Keyboard Level Scaling Right Depth
NRPN 11 | 6 | Keyboard Level Scaling Left Curve
NRPN 12 | 6 | Keyboard Level Scaling Right Curve
NRPN 13 | 6 | Keyboard Rate Scaling
NRPN 14 | 6 | Amp Mod Sensitivity
NRPN 15 | 6 | Keyboard Velocity Sensitivity
NRPN 16 | 6 | Operator Output Level
NRPN 17 | * 6 | Oscillator Mode
NRPN 18 | * 6 | Oscillator Frequency Coarse
NRPN 19 | * 6 | Oscillator Frequency Fine
NRPN 20 | * 6 | Oscillator Detune
NRPN 21 | 5 | Envelope Generator Rate 1
NRPN 22 | 5 | Envelope Generator Rate 2
NRPN 23 | 5 | Envelope Generator Rate 3
NRPN 24 | 5 | Envelope Generator Rate 4
NRPN 25 | 5 | Envelope Generator Level 1
NRPN 26 | 5 | Envelope Generator Level 2
NRPN 27 | 5 | Envelope Generator Level 3
NRPN 28 | 5 | Envelope Generator Level 4
NRPN 29 | 5 | Keyboard Level Scaling Break Point
NRPN 30 | 5 | Keyboard Level Scaling Left Depth
NRPN 31 | 5 | Keyboard Level Scaling Right Depth
NRPN 32 | 5 | Keyboard Level Scaling Left Curve
NRPN 33 | 5 | Keyboard Level Scaling Right Curve
NRPN 34 | 5 | Keyboard Rate Scaling
NRPN 35 | 5 | Amp Mod Sensitivity
NRPN 36 | 5 | Keyboard Velocity Sensitivity
NRPN 37 | 5 | Operator Output Level
NRPN 38 | * 5 | Oscillator Mode
NRPN 39 | * 5 | Oscillator Frequency Coarse
NRPN 40 | * 5 | Oscillator Frequency Fine
NRPN 41 | * 5 | Oscillator Detune
NRPN 42 | 4 | Envelope Generator Rate 1
NRPN 43 | 4 | Envelope Generator Rate 2
NRPN 44 | 4 | Envelope Generator Rate 3
NRPN 45 | 4 | Envelope Generator Rate 4
NRPN 46 | 4 | Envelope Generator Level 1
NRPN 47 | 4 | Envelope Generator Level 2
NRPN 48 | 4 | Envelope Generator Level 3
NRPN 49 | 4 | Envelope Generator Level 4
NRPN 50 | 4 | Keyboard Level Scaling Break Point
NRPN 51 | 4 | Keyboard Level Scaling Left Depth
NRPN 52 | 4 | Keyboard Level Scaling Right Depth
NRPN 53 | 4 | Keyboard Level Scaling Left Curve
NRPN 54 | 4 | Keyboard Level Scaling Right Curve
NRPN 55 | 4 | Keyboard Rate Scaling
NRPN 56 | 4 | Amp Mod Sensitivity
NRPN 57 | 4 | Keyboard Velocity Sensitivity
NRPN 58 | 4 | Operator Output Level
NRPN 59 | * 4 | Oscillator Mode
NRPN 60 | * 4 | Oscillator Frequency Coarse
NRPN 61 | * 4 | Oscillator Frequency Fine
NRPN 62 | * 4 | Oscillator Detune
NRPN 63 | 3 | Envelope Generator Rate 1
NRPN 64 | 3 | Envelope Generator Rate 2
NRPN 65 | 3 | Envelope Generator Rate 3
NRPN 66 | 3 | Envelope Generator Rate 4
NRPN 67 | 3 | Envelope Generator Level 1
NRPN 68 | 3 | Envelope Generator Level 2
NRPN 69 | 3 | Envelope Generator Level 3
NRPN 70 | 3 | Envelope Generator Level 4
NRPN 71 | 3 | Keyboard Level Scaling Break Point
NRPN 72 | 3 | Keyboard Level Scaling Left Depth
NRPN 73 | 3 | Keyboard Level Scaling Right Depth
NRPN 74 | 3 | Keyboard Level Scaling Left Curve
NRPN 75 | 3 | Keyboard Level Scaling Right Curve
NRPN 76 | 3 | Keyboard Rate Scaling
NRPN 77 | 3 | Amp Mod Sensitivity
NRPN 78 | 3 | Keyboard Velocity Sensitivity
NRPN 79 | 3 | Operator Output Level
NRPN 80 | * 3 | Oscillator Mode
NRPN 81 | * 3 | Oscillator Frequency Coarse
NRPN 82 | * 3 | Oscillator Frequency Fine
NRPN 83 | * 3 | Oscillator Detune
NRPN 84 | 2 | Envelope Generator Rate 1
NRPN 85 | 2 | Envelope Generator Rate 2
NRPN 86 | 2 | Envelope Generator Rate 3
NRPN 87 | 2 | Envelope Generator Rate 4
NRPN 88 | 2 | Envelope Generator Level 1
NRPN 89 | 2 | Envelope Generator Level 2
NRPN 90 | 2 | Envelope Generator Level 3
NRPN 91 | 2 | Envelope Generator Level 4
NRPN 92 | 2 | Keyboard Level Scaling Break Point
NRPN 93 | 2 | Keyboard Level Scaling Left Depth
NRPN 94 | 2 | Keyboard Level Scaling Right Depth
NRPN 95 | 2 | Keyboard Level Scaling Left Curve
NRPN 96 | 2 | Keyboard Level Scaling Right Curve
NRPN 97 | 2 | Keyboard Rate Scaling
NRPN 98 | 2 | Amp Mod Sensitivity
NRPN 99 | 2 | Keyboard Velocity Sensitivity
NRPN 100 | 2 | Operator Output Level
NRPN 101 | * 2 | Oscillator Mode
NRPN 102 | * 2 | Oscillator Frequency Coarse
NRPN 103 | * 2 | Oscillator Frequency Fine
NRPN 104 | * 2 | Oscillator Detune
NRPN 105 | 1 | Envelope Generator Rate 1
NRPN 106 | 1 | Envelope Generator Rate 2
NRPN 107 | 1 | Envelope Generator Rate 3
NRPN 108 | 1 | Envelope Generator Rate 4
NRPN 109 | 1 | Envelope Generator Level 1
NRPN 110 | 1 | Envelope Generator Level 2
NRPN 111 | 1 | Envelope Generator Level 3
NRPN 112 | 1 | Envelope Generator Level 4
NRPN 113 | 1 | Keyboard Level Scaling Break Point
NRPN 114 | 1 | Keyboard Level Scaling Left Depth
NRPN 115 | 1 | Keyboard Level Scaling Right Depth
NRPN 116 | 1 | Keyboard Level Scaling Left Curve
NRPN 117 | 1 | Keyboard Level Scaling Right Curve
NRPN 118 | 1 | Keyboard Rate Scaling
NRPN 119 | 1 | Amp Mod Sensitivity
NRPN 120 | 1 | Keyboard Velocity Sensitivity
NRPN 121 | 1 | Operator Output Level
NRPN 122 | * 1 | Oscillator Mode
NRPN 123 | * 1 | Oscillator Frequency Coarse
NRPN 124 | * 1 | Oscillator Frequency Fine
NRPN 125 | * 1 | Oscillator Detune
Fixed Point vs. Floating Point Rendering
========================================
hexter can be compiled to do its sound rendering using either
fixed-point math or floating-point math. The difference in sound
quality should not be audible, so the question of which type of math
to use becomes which type of math is faster. On many older
processors (e.g. PowerPC G4), the fixed-point math is substantially
faster. With newer processors, the speed of each type of math
depends on several factors, including the particular processor, the
compiler and the compiler options used. It is often surprising
which is faster for a given configuration!
On fairly normal posix systems (like Linux or OS X), you can compile
a small test program, to test which type of math is the fastest on
your processor. To do this, unpack the hexter tarball, cd into the
'fptest' directory, type 'make', then type './fptest'. After 30-60
seconds, you should see a summary of the test results.
By default, hexter is built to use fixed-point rendering. If your
test results say that floating-point is faster, then you can
configure hexter to use floating-point with the
'--enable-floating-point' configure option.
Here are some test results from a few machines. Lower percentages
indicate the faster mode.
Processor Fixed Point Floating Point
------------------------------------- ----------- --------------
PowerPC G4 800MHz 49.5% 100.0%
PowerPC G4 1.07GHz 49.8% 100.0%
Pentium III (Coppermine) 933MHz 100.0% 95.2%
Intel Core Duo 1.83GHz, OS X 10.4.9 100.0% 92.9%
Intel Core 2 Duo 2.4GHz, Linux 3.2 100.0% 96.1% *
Intel Core 2 Duo 2.4GHz, OS X 10.4.11 100.0% 91.4% *
Intel Core 2 Duo 2.4GHz, OS X 10.6.8 61.5% 100.0% *
Intel Core 2 Duo 2.5GHz, OS X 10.6.7 62.0% 100.0%
Intel Core i7, OS X 10.7 52.0% 100.0%
* These three all come from the same machine!
Frequently Asked Questions
==========================
Q. The plugin seems to work fine, but the GUI never appears. Why?
A. Make sure the hostname of your machine is resolvable (if not, the
OSC messages can't be sent between host and GUI). If your machine's
hostname is 'foo.bar.net', make sure you either have an entry for
'foo.bar.net' in /etc/hosts, or that your DNS server can resolve it.
Test this with e.g. 'ping foo.bar.net'. To test that the GUI itself
works, you can start it by itself (without a DSSI host) by giving it
the '-test' option, for example:
$ /lib/dssi/hexter/hexter_gtk -test
Resources:
==========
http://en.wikipedia.org/wiki/Yamaha_DX7
The Wikipedia Yamaha DX7 page.
http://homepage.ntlworld.com/steve.sims/
Steve Sims' site with lots of information, patches, and links.
http://homepages.abdn.ac.uk/mth192/pages/html/dx7.html
Dave Benson's DX7 page, has much info as well as links to patch
files.
http://www.synthzone.com/yamaha.htm
The Synth Zone's collection of Yamaha links, which contains quite
a few links to patch file collections.
hexter-1.0.2/ChangeLog 0000644 0000764 0000764 00000012534 12046775374 011540 0000000 0000000 20121108 smbolton -- version 1.0.2
* Fixed: starting the GUI on a session with unsaved edits would
leave the patch editor insensitive (thanks to William Light for
the bug report.)
20121102 smbolton -- version 1.0.1
* Didn't I already fix that missing '-lm' thing everywhere already?
20121029 smbolton -- version 1.0.0
* Merged patched editors.
* Merged DX-7 to UTF-8 character set conversion.
* Fixed test note code to prevent stuck notes.
20121023 smbolton
* Merged debug branch.
20121022 smbolton
* hexter development is now hosted on github:
https://github.com/smbolton/hexter
* More patch loading enhancements from Martin Tarenskeen.
20110628 CVS commit smbolton -- version 0.6.9.0
* MIDI non-registered parameters (NRPNs) can now be used to change
any of the operator parameters for a plugin instance's current
patch on-the-fly. Thanks to Jamie Bullock for contributing this
code.
* It is now possible to ./configure hexter to build the GTK+ user
interface, the text-mode UI, both, or neither (again, thanks to
Jamie).
* The GTK+ GUI now requires GTK+ 2.4 or later.
* hexter may now be built to use floating-point math in its audio
rendering. There is a new '--enable-floating-point' ./configure
option, and a simple test harness in the fptest/ directory.
* Both the hexter GUI and tx_edit include even more patch loading
enhancements from Martin Tarenskeen.
* The synthesis code has been simplified, so the once-separate car()
and mod() functions are now just a single op(), which means less
cache pressure for both code and data.
* There should be some other minor speed-ups as well: removed a
bunch of slow unsigned to float casts, and fixed some constant
expressions that were not being optimized.
* Oops. GUI 'sample-rate' method broke 'quit'.
* GUI no longer segfaults if started with no arguments.
20090103 version 0.6.2
* Silently ignore 'sample-rate' method.
* Fixed GtkSpinButton adjustments to avoid page_size warning with
GTK+ >=2.14.
* Added Martin Tarenskeen's patch loading enhancements to
extra/tx_edit.c.
20070411 version 0.6.1
* hexter now installs as DSSI plugin 'hexter', just like the 0.5.9
and earlier versions, eliminating the trouble the versioned
plugin names would cause distribution packagers. The plugin
files installed are again:
/lib/dssi/hexter/hexter_gtk
/lib/dssi/hexter.so
/lib/dssi/hexter.la
Also, there is now a 'disable LFO/Mod/Perf (0.5.x compatibility)'
option in the hexter GUI which disables the version 0.6.x LFO,
amplitude and pitch modulation functions, allowing projects made
with version 0.5.9 to sound as they were originally created.
20070118 version 0.6.0
* hexter version 0.6.0 installed as DSSI plugin 'hexter6', with the
following files:
/lib/dssi/hexter6/hexter6_gtk
/lib/dssi/hexter6.so
/lib/dssi/hexter6.la
This allowed hexter 0.5.9 to be installed alongside the 0.6.0
version, but was a headache for distribution packagers, so this
was abandoned with version 0.6.1.
* Implemented the LFO, amplitude modulation and pitch modulation
(many thanks to Jamie Bullock!)
* Added TX7-style performance parameters, allowing configuration
from the GUI of pitch bend range, portamento time, and
sensitivity and assignment of the modulation wheel, foot
controller, pressure (both channel and key), and breath
controller.
* Added DX7 patchbank loading code from Martin Tarenskeen, allowing
hexter to load a number of additional patch file formats.
* Partially implemented portamento. For now, the curves and times
are wrong, but the plumbing is there.
20060108 version 0.5.9
* Added GUI '-test' magic host URL argument for starting GUI without
a host.
* Improved the 'About' dialog with a new color pixmap.
* Fixed the held key tracking.
* Use gcc/glibc 'constructor' and 'destructor' attributes instead of
the deprecated _init() and _fini() functions (needed for OS X
10.4 'Tiger').
20051024 CVS commit smbolton
* Added support for change operator coarse frequency in real time
via MIDI binding (for the Harvey Project).
* Minor gcc4 fixes.
20050411 CVS commit smbolton
* Initial Mac OS X support (sys-ex patch edit reception is still
ALSA-only.)
20050119 CVS commit smbolton
( version bump to 0.5.9 )
* gcc 2.9x '-finline-limit=5000' fix in configure.in
* RPM bindir fix in src/Makefile.am
20041229 version 0.5.8
* Added a 'Volume' control, and implemented MIDI CC 7 'Volume'
handling.
* Compiles with GTK+ 2.x by default, or with GTK+ 1.2 if 2.x is not
found. An optional text (readline) based UI can be built
instead by supplying configure with the '--with-textui' flag.
* Implemented DSSI project directory handling.
* Changed activate() to new behavior.
* Fixed bug where changes to tuning control would only effect first
playing voice.
* Made a number of error messages more informational.
* Added converted FB-01 patches.
20041101 0.5.7 first public release
* Moved Test Note frame to be visible when both Patches and
Configuration tabs are selected.
* Changed tuning slider to a spinbutton for greater accuracy.
* Made a slightly better default patch set.
20041029 0.5.7-alpha -- initial alpha release
* "don't put that in your mouth, you don't know where it's been!"
hexter-1.0.2/TODO 0000644 0000764 0000764 00000001140 12041434775 010435 0000000 0000000 hexter To-Do list, in no particular order:
==========================================
* Clean up all "!FIX!"es (and "-FIX-"es).
* Optionally sort patch list alphabetically (Steve Harris).
* optimize so if a voice just being set up still has all the
patch data for the current edit buffer, we skip loading it.
* Figure out the feedback scaling "fudge factor". The current 0.18
is close, but not right on.
* Finish pitch envelope time calculation stuff.
* Add a high-pass filter to the output, to block very low frequency
output like the DX7 does.
* Implement de-clicking of stolen voices.
hexter-1.0.2/COPYING 0000644 0000764 0000764 00000043103 11757613235 011010 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
hexter-1.0.2/extra/ 0000755 0000764 0000764 00000000000 12046775671 011164 5 0000000 0000000 hexter-1.0.2/extra/textui_main.c 0000644 0000764 0000764 00000024367 11757613235 013605 0000000 0000000 /* hexter DSSI software synthesizer text-mode UI
*
* Copyright (C) 2004, 2009 Sean Bolton and others.
*
* Portions of this file may have come from Chris Cannam and Steve
* Harris's public domain DSSI example code.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include "hexter_types.h"
#include "hexter.h"
#include "gui_main.h"
#include "textui_callbacks.h"
/* -FIX- #include "gui_midi.h" */
#include "gui_data.h"
#include "dx7_voice_data.h"
/* ==== global variables ==== */
char *user_friendly_id;
char * osc_host_url;
char * osc_self_url;
lo_address osc_host_address;
char * osc_configure_path;
char * osc_control_path;
char * osc_exiting_path;
char * osc_hide_path;
char * osc_midi_path;
char * osc_program_path;
char * osc_quit_path;
char * osc_show_path;
char * osc_update_path;
dx7_patch_t *patches = NULL;
int patch_section_dirty[4];
int current_program = 0;
int edit_buffer_active = 0;
edit_buffer_t edit_buffer;
int edit_receive_channel = 0;
int done = 0;
int host_requested_quit = 0;
/* ==== OSC handling ==== */
static char *
osc_build_path(char *base_path, char *method)
{
char buffer[256];
char *full_path;
snprintf(buffer, 256, "%s%s", base_path, method);
if (!(full_path = strdup(buffer))) {
TUIDB_MESSAGE(DB_OSC, ": out of memory!\n");
exit(1);
}
return strdup(buffer);
}
static void
osc_error(int num, const char *msg, const char *path)
{
TUIDB_MESSAGE(DB_OSC, " error: liblo server error %d in path \"%s\": %s\n",
num, (path ? path : "(null)"), msg);
}
int
osc_debug_handler(const char *path, const char *types, lo_arg **argv,
int argc, lo_message msg, void *user_data)
{
int i;
TUIDB_MESSAGE(DB_OSC, " warning: unhandled OSC message to <%s>:\n", path);
for (i = 0; i < argc; ++i) {
printf("arg %d: type '%c': ", i, types[i]);
lo_arg_pp((lo_type)types[i], argv[i]);
printf("\n");
}
return 1; /* try any other handlers */
}
int
osc_action_handler(const char *path, const char *types, lo_arg **argv,
int argc, lo_message msg, void *user_data)
{
if (!strcmp(user_data, "show")) {
/* TUIDB_MESSAGE(DB_OSC, " osc_action_handler: received 'show' message\n"); */
} else if (!strcmp(user_data, "hide")) {
/* TUIDB_MESSAGE(DB_OSC, " osc_action_handler: received 'hide' message\n"); */
} else if (!strcmp(user_data, "quit")) {
/* TUIDB_MESSAGE(DB_OSC, " osc_action_handler: received 'quit' message\n"); */
host_requested_quit = 1;
done = 1;
} else {
return osc_debug_handler(path, types, argv, argc, msg, user_data);
}
return 0;
}
int
osc_configure_handler(const char *path, const char *types, lo_arg **argv,
int argc, lo_message msg, void *user_data)
{
char *key, *value;
if (argc < 2) {
TUIDB_MESSAGE(DB_OSC, " error: too few arguments to osc_configure_handler\n");
return 1;
}
key = &argv[0]->s;
value = &argv[1]->s;
if (strlen(key) == 8 && !strncmp(key, "patches", 7) &&
key[7] >= '0' && key[7] <= '3') {
update_patches(key, value);
} else if (!strcmp(key, "edit_buffer")) {
/* -FIX- update_edit_buffer(value); */
} else if (!strcmp(key, "monophonic")) {
update_monophonic(value);
} else if (!strcmp(key, "polyphony")) {
update_polyphony(value);
#ifdef DSSI_GLOBAL_CONFIGURE_PREFIX
} else if (!strcmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX "polyphony")) {
#else
} else if (!strcmp(key, "global_polyphony")) {
#endif
update_global_polyphony(value);
#ifdef DSSI_PROJECT_DIRECTORY_KEY
} else if (!strcmp(key, DSSI_PROJECT_DIRECTORY_KEY)) {
/* -FIX- implement project directory key */
#endif
} else {
return osc_debug_handler(path, types, argv, argc, msg, user_data);
}
return 0;
}
int
osc_control_handler(const char *path, const char *types, lo_arg **argv,
int argc, lo_message msg, void *user_data)
{
int port;
float value;
if (argc < 2) {
TUIDB_MESSAGE(DB_OSC, " error: too few arguments to osc_control_handler\n");
return 1;
}
port = argv[0]->i;
value = argv[1]->f;
TUIDB_MESSAGE(DB_OSC, " osc_control_handler: control %d now %f\n", port, value);
/* -FIX- update_voice_widget(port, value); */
return 0;
}
int
osc_program_handler(const char *path, const char *types, lo_arg **argv,
int argc, lo_message msg, void *user_data)
{
int bank, program;
if (argc < 2) {
TUIDB_MESSAGE(DB_OSC, " error: too few arguments to osc_program_handler\n");
return 1;
}
bank = argv[0]->i;
program = argv[1]->i;
if (bank || program < 0 || program > 127) {
TUIDB_MESSAGE(DB_OSC, ": out-of-range program select (bank %d, program %d)\n", bank, program);
return 0;
}
TUIDB_MESSAGE(DB_OSC, " osc_program_handler: received program change, bank %d, program %d\n", bank, program);
update_from_program_select(bank, program);
return 0;
}
/* ==== main ==== */
int
main(int argc, char *argv[])
{
char *host, *port, *path, *tmp_url, *rl_prompt;
lo_server osc_server;
int lo_fd, ret;
fd_set fds;
DSSP_DEBUG_INIT("hexter_text");
#ifdef DSSP_DEBUG
TUIDB_MESSAGE(DB_MAIN, " starting (pid %d)...\n", getpid());
#else
printf("hexter_text starting (pid %d)...\n", getpid());
#endif
/* { int i; fprintf(stderr, "args:\n"); for(i=0; i \n", argv[0]);
exit(1);
}
user_friendly_id = argv[4];
/* set up OSC support */
osc_host_url = argv[1];
host = lo_url_get_hostname(osc_host_url);
port = lo_url_get_port(osc_host_url);
path = lo_url_get_path(osc_host_url);
osc_host_address = lo_address_new(host, port);
osc_configure_path = osc_build_path(path, "/configure");
osc_control_path = osc_build_path(path, "/control");
osc_exiting_path = osc_build_path(path, "/exiting");
osc_hide_path = osc_build_path(path, "/hide");
osc_midi_path = osc_build_path(path, "/midi");
osc_program_path = osc_build_path(path, "/program");
osc_quit_path = osc_build_path(path, "/quit");
osc_show_path = osc_build_path(path, "/show");
osc_update_path = osc_build_path(path, "/update");
osc_server = lo_server_new(NULL, osc_error);
lo_server_add_method(osc_server, osc_configure_path, "ss", osc_configure_handler, NULL);
lo_server_add_method(osc_server, osc_control_path, "if", osc_control_handler, NULL);
lo_server_add_method(osc_server, osc_hide_path, "", osc_action_handler, "hide");
lo_server_add_method(osc_server, osc_program_path, "ii", osc_program_handler, NULL);
lo_server_add_method(osc_server, osc_quit_path, "", osc_action_handler, "quit");
lo_server_add_method(osc_server, osc_show_path, "", osc_action_handler, "show");
lo_server_add_method(osc_server, NULL, NULL, osc_debug_handler, NULL);
tmp_url = lo_server_get_url(osc_server);
osc_self_url = osc_build_path(tmp_url, (strlen(path) > 1 ? path + 1 : path));
free(tmp_url);
/* get OSC server socket fd for main loop select() */
lo_fd = lo_server_get_socket_fd(osc_server);
if (lo_fd < 0) {
printf("hexter_text fatal: OSC transport does not support exposing socket fd\n");
exit(1);
}
/* set up patches */
gui_data_patches_init();
/* set up readline */
rl_prompt = (char *)malloc(strlen(user_friendly_id) + 12); // error handling....
sprintf(rl_prompt, "hexter %s> ", user_friendly_id);
rl_callback_handler_install (rl_prompt, readline_callback);
rl_add_defun("test-note", test_note_callback, CTRL('t'));
/* send our update request */
lo_send(osc_host_address, osc_update_path, "s", osc_self_url);
/* main loop */
do {
/* set up list of file descriptors to watch */
FD_ZERO(&fds);
FD_SET(0, &fds); /* stdin */
FD_SET(lo_fd, &fds);
ret = select(lo_fd + 1, &fds, NULL, NULL, NULL);
if (ret == -1) {
printf("hexter_text fatal: main loop select() error!\n");
done = 1;
} else if (ret > 0) {
if (FD_ISSET(0, &fds)) {
rl_callback_read_char();
}
if (FD_ISSET(lo_fd, &fds)) {
lo_server_recv_noblock(osc_server, 0);
}
}
} while (!done);
/* clean up and exit */
TUIDB_MESSAGE(DB_MAIN, ": yep, we got to the cleanup!\n");
/* shut down sys-ex receive, if enabled */
/* -FIX- if (sysex_enabled) {
* sysex_stop();
* } */
/* readline cleanup */
rl_callback_handler_remove();
/* say bye-bye */
if (!host_requested_quit) {
lo_send(osc_host_address, osc_exiting_path, "");
}
/* clean up patches */
gui_data_patches_free();
/* clean up OSC support */
lo_server_free(osc_server);
free(host);
free(port);
free(path);
free(osc_configure_path);
free(osc_control_path);
free(osc_exiting_path);
free(osc_hide_path);
free(osc_midi_path);
free(osc_program_path);
free(osc_quit_path);
free(osc_show_path);
free(osc_update_path);
free(osc_self_url);
return 0;
}
hexter-1.0.2/extra/tx_edit.c 0000644 0000764 0000764 00000227142 12044027035 012676 0000000 0000000 /* Yamaha DX7 / TX7 Editor/Librarian
*
* Copyright (C) 1991, 1995, 1997, 1998, 2004, 2009, 2011,
* 2012 Sean Bolton.
*
* This is an ncurses-based patch editor for the Yamaha DX7 and
* TX7. It is provided as-is, without any documentation, and
* is totally unsupported, but may be useful to you if you can't use
* JSynthLib or similar. It started out life on my Apple ][+, then
* I ported it to my Amiga, then to my MS-DOS machine, then to
* Linux, so the code's a mess and nothing I'm proud of. But, it
* does the job.
*
* Compile with:
* gcc -o tx_edit tx_edit.c -lcurses -lasound
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Revision History:
* 20040126 Sean Bolton - made help functions helpful, added ALSA support
* 20040205 Sean Bolton - clean up display with noecho, line drawing
* 20040207 Sean Bolton - add next/previous voice commands to edit mode
* 20090102 Sean Bolton - incorporated Martin Tarenskeen's patch loading
* enhancements
* 20110215 Sean Bolton - incorporated more patch loading enhancements
* from Martin Tarenskeen.
* 20121022 Sean Bolton - and yet more from Martin.
*/
/* Need to do: */
/* need to provide color changing option */
/* bank and single receive */
/* auto buffer sizing? */
/* a search option would be nice */
/* show channel/instrument on display */
#define VERSIONSTRING "0.94s"
/* Undefine USE_ALSA_MIDI to just write to /dev/midi */
#define USE_ALSA_MIDI 1
#define DEBUG 1
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef USE_ALSA_MIDI
#include
#endif
#define RETURN_OK 0
#define RETURN_FAIL 255
typedef unsigned char UBYTE;
void cprintf(const char *fmt, ...);
/* ==== Files ==== */
#define MAXPATH 80
char FNameBuff[MAXPATH]="\0";
/* ==== Buffers ==== */
#define DEFAULTVOICES 8192
#define DX7_VOICE_SIZE_PACKED 128
#define DX7_VOICE_SIZE_UNPACKED 155
#define DX7_DUMP_SIZE_VOICE_SINGLE 155+8
#define DX7_DUMP_SIZE_VOICE_BULK 4096+8
int Voices = DEFAULTVOICES;
UBYTE *Buffer = NULL,
*VoiceData,
*SingleDump,
*SingleData,
*BulkDump;
int BufferLength;
/* ==== Console ==== */
#define KEY_METAA (0x200+'a')
#define KEY_METAB (0x200+'b')
#define KEY_METAC (0x200+'c')
#define KEY_METAD (0x200+'d')
#define KEY_METAE (0x200+'e')
#define KEY_METAG (0x200+'g')
#define KEY_METAH (0x200+'h')
#define KEY_METAL (0x200+'l')
#define KEY_METAM (0x200+'m')
#define KEY_METAO (0x200+'o')
#define KEY_METAP (0x200+'p')
#define KEY_METAQ (0x200+'q')
#define KEY_METAR (0x200+'r')
#define KEY_METAS (0x200+'s')
#define KEY_METAT (0x200+'t')
#undef KEY_ENTER
#define KEY_ENTER (0x0a)
#define KEY_ESC (0x1b)
#define KEY_METAEQ (0x200+'=') /* Alt-= */
#define KEY_METAPL (0x200+'+') /* Alt-+ */
#define KEY_METAEX (0x200+'!') /* Alt-! */
#define KEY_METANU (0x200+'#') /* Alt-# */
enum textcolor {COLOR_MSG = 1, COLOR_LABEL, COLOR_DATA, COLOR_BLOCK,
COLOR_CURSOR, COLOR_BCURSOR, COLOR_OPON, COLOR_OPOFF};
#if 0
#define kc_Del (0x5300)
#define kc_CtrlRight (0x7400)
#define kc_CtrlLeft (0x7300)
#define kc_CtrlPgUp (0x8400)
#define kc_CtrlPgDn (0x7600)
#define kc_Home (0x4700)
#define kc_End (0x4f00)
#define kc_CtrlHome (0x7700)
#define kc_CtrlEnd (0x7500)
#endif
/* ==== Midi ==== */
#ifdef USE_ALSA_MIDI
snd_seq_t *MidiHandle = NULL;
int MidiClient;
int MidiPort = -1;
#endif
char TXChannel = 0; /* 0-15! */
/* ==== VoiceEdit ==== */
#define VOICEPARMS 146
#define VOICEPARMMAX 145
#ifdef USE_CALCED_CURSOR_MOVES
#define VOICEPARMS_X_SPAN 57
#define VOICEPARMS_Y_SPAN 18
#endif
int ve_Cursor = 0;
int ve_OpSelect = 63;
#define vptName 1
#define vpt0_99 2
#define vpt0_7 3
#define vptMode 4 /* R,F */
#define vptFC 5 /* 0-31 */
#define vptFF 6 /* 0-99 */
#define vptDetune 7 /* 0-14, as -7-+7 */
#define vpt0_3 8
#define vptAlg 9 /* 0-31, as 1-32 */
#define vptCurve 10 /* 0-3, scaling curve */
#define vptBkPt 11 /* 0-99, breakpoint */
#define vptTrans 12 /* 0-48, transpose */
#define vptOnOff 13
#define vptWave 14
unsigned char vtypemax[15] = {
0, 0, 99, 7, 1, 31, 99, 14, 3, 31, 3, 99, 48, 1, 5,
};
struct _veParm {
UBYTE Type;
UBYTE Offset;
UBYTE X;
UBYTE Y;
UBYTE Up; /* -FIX- Up and Down are obsolete with calc'ed cursor moves */
UBYTE Down;
} veParm[VOICEPARMS] = {
/* T, Off, X, Y, U, D */
{ 1, 145, 31, 0, 145, 8, }, /* Name */
{ 2, 105, 5, 4, 140, 17, }, /* O1 R1 */
{ 2, 109, 8, 4, 141, 18, },
{ 2, 106, 12, 4, 142, 19, },
{ 2, 110, 15, 4, 142, 20, },
{ 2, 107, 19, 4, 143, 21, },
{ 2, 111, 22, 4, 144, 22, },
{ 2, 108, 26, 4, 0, 23, },
{ 2, 112, 29, 4, 0, 24, },
{ 3, 118, 33, 4, 0, 25, }, /* O1 RS */
{ 4, 122, 36, 4, 0, 26, },
{ 5, 123, 38, 4, 145, 27, },
{ 6, 124, 41, 4, 121, 28, },
{ 7, 125, 44, 4, 121, 29, },
{ 2, 121, 54, 4, 94, 30, },
{ 3, 120, 58, 4, 95, 31, },
{ 8, 119, 60, 4, 96, 32, }, /* O1 AMS */
{ 2, 84, 5, 5, 1, 33, }, /* O2 R1 */
{ 2, 88, 8, 5, 2, 34, },
{ 2, 85, 12, 5, 3, 35, },
{ 2, 89, 15, 5, 4, 36, },
{ 2, 86, 19, 5, 5, 37, },
{ 2, 90, 22, 5, 6, 38, },
{ 2, 87, 26, 5, 7, 39, },
{ 2, 91, 29, 5, 8, 40, },
{ 3, 97, 33, 5, 9, 41, }, /* O2 RS */
{ 4, 101, 36, 5, 10, 42, },
{ 5, 102, 38, 5, 11, 43, },
{ 6, 103, 41, 5, 12, 44, },
{ 7, 104, 44, 5, 13, 45, },
{ 2, 100, 54, 5, 14, 46, },
{ 3, 99, 58, 5, 15, 47, },
{ 8, 98, 60, 5, 16, 48, }, /* O2 AMS */
{ 2, 63, 5, 6, 17, 49, }, /* O3 R1 */
{ 2, 67, 8, 6, 18, 50, },
{ 2, 64, 12, 6, 19, 51, },
{ 2, 68, 15, 6, 20, 52, },
{ 2, 65, 19, 6, 21, 53, },
{ 2, 69, 22, 6, 22, 54, },
{ 2, 66, 26, 6, 23, 55, },
{ 2, 70, 29, 6, 24, 56, },
{ 3, 76, 33, 6, 25, 57, }, /* O3 RS */
{ 4, 80, 36, 6, 26, 58, },
{ 5, 81, 38, 6, 27, 59, },
{ 6, 82, 41, 6, 28, 60, },
{ 7, 83, 44, 6, 29, 61, },
{ 2, 79, 54, 6, 30, 62, },
{ 3, 78, 58, 6, 31, 63, },
{ 8, 77, 60, 6, 32, 64, }, /* O3 AMS */
{ 2, 42, 5, 7, 33, 65, }, /* O4 R1 */
{ 2, 46, 8, 7, 34, 66, },
{ 2, 43, 12, 7, 35, 67, },
{ 2, 47, 15, 7, 36, 68, },
{ 2, 44, 19, 7, 37, 69, },
{ 2, 48, 22, 7, 38, 70, },
{ 2, 45, 26, 7, 39, 71, },
{ 2, 49, 29, 7, 40, 72, },
{ 3, 55, 33, 7, 41, 73, }, /* O4 RS */
{ 4, 59, 36, 7, 42, 74, },
{ 5, 60, 38, 7, 43, 75, },
{ 6, 61, 41, 7, 44, 76, },
{ 7, 62, 44, 7, 45, 77, },
{ 2, 58, 54, 7, 46, 78, },
{ 3, 57, 58, 7, 47, 79, },
{ 8, 56, 60, 7, 48, 80, }, /* O4 AMS */
{ 2, 21, 5, 8, 49, 81, }, /* O5 R1 */
{ 2, 25, 8, 8, 50, 82, },
{ 2, 22, 12, 8, 51, 83, },
{ 2, 26, 15, 8, 52, 84, },
{ 2, 23, 19, 8, 53, 85, },
{ 2, 27, 22, 8, 54, 86, },
{ 2, 24, 26, 8, 55, 87, },
{ 2, 28, 29, 8, 56, 88, },
{ 3, 34, 33, 8, 57, 89, }, /* O5 RS */
{ 4, 38, 36, 8, 58, 90, },
{ 5, 39, 38, 8, 59, 91, },
{ 6, 40, 41, 8, 60, 92, },
{ 7, 41, 44, 8, 61, 93, },
{ 2, 37, 54, 8, 62, 94, },
{ 3, 36, 58, 8, 63, 95, },
{ 8, 35, 60, 8, 64, 96, }, /* O5 AMS */
{ 2, 0, 5, 9, 65, 97, }, /* O6 R1 */
{ 2, 4, 8, 9, 66, 98, },
{ 2, 1, 12, 9, 67, 99, },
{ 2, 5, 15, 9, 68, 100, },
{ 2, 2, 19, 9, 69, 101, },
{ 2, 6, 22, 9, 70, 102, },
{ 2, 3, 26, 9, 71, 103, },
{ 2, 7, 29, 9, 72, 104, },
{ 3, 13, 33, 9, 73, 106, }, /* O6 RS */
{ 4, 17, 36, 9, 74, 106, },
{ 5, 18, 38, 9, 75, 106, },
{ 6, 19, 41, 9, 76, 105, },
{ 7, 20, 44, 9, 77, 105, },
{ 2, 16, 54, 9, 78, 105, },
{ 3, 15, 58, 9, 79, 105, },
{ 8, 14, 60, 9, 80, 105, }, /* O6 AMS */
{ 2, 126, 5, 10, 81, 108, }, /* P R1 */
{ 2, 130, 8, 10, 82, 109, },
{ 2, 127, 12, 10, 83, 110, },
{ 2, 131, 15, 10, 84, 110, },
{ 2, 128, 19, 10, 85, 111, },
{ 2, 132, 22, 10, 86, 112, },
{ 2, 129, 26, 10, 87, 112, },
{ 2, 133, 29, 10, 88, 106, },
{ 9, 134, 48, 11, 94, 107, }, /* Alg */
{ 2, 137, 35, 12, 90, 113, },
{ 3, 135, 49, 12, 105, 114, },
{ 10, 116, 5, 13, 97, 115, }, /* O1 LC */
{ 2, 114, 10, 13, 98, 116, },
{ 11, 113, 13, 13, 99, 117, },
{ 10, 117, 18, 13, 101, 118, },
{ 2, 115, 23, 13, 102, 119, },
{ 2, 138, 35, 13, 106, 120, }, /* Delay */
{ 12, 144, 46, 13, 107, 121, },
{ 10, 95, 5, 14, 108, 122, }, /* O2 LC */
{ 2, 93, 10, 14, 109, 123, },
{ 11, 92, 13, 14, 110, 124, },
{ 10, 96, 18, 14, 111, 125, },
{ 2, 94, 23, 14, 112, 126, },
{ 2, 139, 35, 14, 113, 127, }, /* PMD */
{ 13, 136, 47, 14, 114, 14, },
{ 10, 74, 5, 15, 115, 128, }, /* O3 LC */
{ 2, 72, 10, 15, 116, 129, },
{ 11, 71, 13, 15, 117, 130, },
{ 10, 75, 18, 15, 118, 131, },
{ 2, 73, 23, 15, 119, 132, },
{ 2, 140, 35, 15, 120, 133, }, /* AMD */
{ 10, 53, 5, 16, 122, 134, }, /* O4 LC */
{ 2, 51, 10, 16, 123, 135, },
{ 11, 50, 13, 16, 124, 136, },
{ 10, 54, 18, 16, 125, 137, },
{ 2, 52, 23, 16, 126, 138, },
{ 13, 141, 34, 16, 127, 139, }, /* Sync */
{ 10, 32, 5, 17, 128, 140, }, /* O5 LC */
{ 2, 30, 10, 17, 129, 141, },
{ 11, 29, 13, 17, 130, 142, },
{ 10, 33, 18, 17, 131, 143, },
{ 2, 31, 23, 17, 132, 144, },
{ 14, 142, 34, 17, 133, 145, }, /* Wave */
{ 10, 11, 5, 18, 134, 1, }, /* O6 LC */
{ 2, 9, 10, 18, 135, 2, },
{ 11, 8, 13, 18, 136, 3, },
{ 10, 12, 18, 18, 137, 5, },
{ 2, 10, 23, 18, 138, 6, },
{ 3, 143, 36, 18, 139, 10, } /* PMS */
};
unsigned short veFFF[100] = {
1000, 1023, 1047, 1072, 1096, 1122, 1148, 1175, 1202, 1230,
1259, 1288, 1318, 1349, 1380, 1413, 1445, 1479, 1514, 1549,
1585, 1622, 1660, 1698, 1738, 1778, 1820, 1862, 1905, 1950,
1995, 2042, 2089, 2138, 2188, 2239, 2291, 2344, 2399, 2455,
2512, 2570, 2630, 2692, 2754, 2818, 2884, 2951, 3020, 3090,
3162, 3236, 3311, 3388, 3467, 3548, 3631, 3715, 3802, 3890,
3981, 4074, 4169, 4266, 4365, 4467, 4571, 4677, 4786, 4898,
5012, 5129, 5248, 5370, 5495, 5623, 5754, 5888, 6026, 6166,
6310, 6457, 6607, 6761, 6918, 7079, 7244, 7413, 7586, 7762,
7943, 8128, 8318, 8511, 8710, 8913, 9120, 9333, 9550, 9772,
};
/* ==== Algorithm ==== */
char *veAlg[32] = { /* 32 algs, max 9 high and 17 wide */
" '`\n" /* 1 */
" 6/\n"
" |\n"
" 5\n"
" |\n"
"2 4\n"
"| |\n"
"1 3\n"
"L--/",
"\n" /* 2 */
" 6\n"
" |\n"
" 5\n"
"'` |\n"
"2/ 4\n"
"| |\n"
"1 3\n"
"L--/",
" '`\n" /* 3 */
"3 6/\n"
"| |\n"
"2 5\n"
"| |\n"
"1 4\n"
"L--/",
" '`\n" /* 4 */
"3 6|\n"
"| ||\n"
"2 5|\n"
"| ||\n"
"1 4/\n"
"L--/",
" '`\n" /* 5 */
"2 4 6/\n"
"| | |\n"
"1 3 5\n"
"L--^--/",
" '`\n" /* 6 */
"2 4 6|\n"
"| | ||\n"
"1 3 5/\n"
"L--^--/",
" '`\n" /* 7 */
" 6/\n"
" |\n"
"2 4 5\n"
"| }--/\n"
"1 3\n"
"L--/",
"\n" /* 8 */
" 6\n"
" '` |\n"
"2 4/ 5\n"
"| }--/\n"
"1 3\n"
"L--/",
"\n" /* 9 */
" 6\n"
"'` |\n"
"2/ 4 5\n"
"| }--/\n"
"1 3\n"
"L--/",
"'`\n" /* 10 */
"3/\n"
"|\n"
"2 5 6\n"
"| }--/\n"
"1 4\n"
"L--/",
"\n" /* 11 */
"3\n"
"| '`\n"
"2 5 6/\n"
"| }--/\n"
"1 4\n"
"L--/",
"'`\n" /* 12 */
"2/ 4 5 6\n"
"| L--+--/\n"
"1 3\n"
"L-----/",
" '`\n" /* 13 */
"2 4 5 6/\n" /* 13 */
"| L--+--/\n"
"1 3\n"
"L-----/",
" '`\n" /* 14 */
" 5 6/\n"
" }--/\n"
"2 4\n"
"| |\n"
"1 3\n"
"L--/",
"\n" /* 15 */
" 5 6\n"
"'` }--/\n"
"2/ 4\n"
"| |\n"
"1 3\n"
"L--/",
" '`\n" /* 16 */
" 4 6/\n"
" | |\n"
"2 3 5\n"
"L--+--/\n"
" 1",
"\n" /* 17 */
" 4 6\n"
"'` | |\n"
"2/ 3 5\n"
"L--+--/\n"
" 1",
" 6\n" /* 18 */
" |\n"
" 5\n"
" '` |\n"
"2 3/ 4\n"
"L--+--/\n"
" 1",
"3\n" /* 19 */
"| '`\n"
"2 6/\n"
"| }--`\n"
"1 4 5\n"
"L--^--/",
"'`\n" /* 20 */
"3/ 5 6\n"
"}--` }--/\n"
"1 2 4\n"
"L--^--/",
"'`\n" /* 21 */
"3/ 6\n"
"}--` }--`\n"
"1 2 4 5\n"
"L--^--^--/",
" '`\n" /* 22 */
"2 6/\n"
"| '--+--`\n"
"1 3 4 5\n"
"L--^--^--/",
" '`\n" /* 23 */
" 3 6/\n"
" | }--`\n"
"1 2 4 5\n"
"L--^--^--/",
" '`\n" /* 24 */
" 6/\n"
" '--+--`\n"
"1 2 3 4 5\n"
"L--^--^--^--/",
" '`\n" /* 25 */
" 6/\n"
" }--`\n"
"1 2 3 4 5\n"
"L--^--^--^--/",
" '`\n" /* 26 */
" 3 5 6/\n"
" | }--/\n"
"1 2 4\n"
"L--^--/",
" '`\n" /* 27 */
" 3/ 5 6\n"
" | }--/\n"
"1 2 4\n"
"L--^--/",
" '`\n" /* 28 */
" 5/\n"
" |\n"
"2 4\n"
"| |\n"
"1 3 6\n"
"L--^--/",
" '`\n" /* 29 */
" 4 6/\n"
" | |\n"
"1 2 3 5\n"
"L--^--^--/",
" '`\n" /* 30 */
" 5/\n"
" |\n"
" 4\n"
" |\n"
"1 2 3 6\n"
"L--^--^--/",
" '`\n"
" 6/\n" /* 31 */
" |\n"
"1 2 3 4 5\n"
"L--^--^--^--/",
" '`" /* 32 */
"1 2 3 4 5 6/"
"L--^--^--^--^--/",
};
/* ==== Librarian ==== */
void noop(void){}
void (*LibBlockAction)(void) = noop;
int Voice_Cursor = 0, /* voice number under curser */
Voice_TOS = 0, /* " at top of screen */
Voice_BMark, /* " where block first marked */
Voice_BStart, /* " of block start */
Voice_BEnd; /* " of block end */
bool blocking = FALSE,
blocked = FALSE;
/* -FIX- This should be dynamic! */
int LibCols=5, /* columns of names that fit on screen (15 char each) */
LibRows=16, /* rows of names that fit on screen */
LibNames=80; /* names that fit on screen */
/* ==== Control ==== */
int txmode=0,
newmode=0;
#define MODELIB 1
#define MODEEDIT 2
#define MODEQUIT 3
/* ==== Utility Stuff ==== */
inline int min(int a, int b) { return (a < b ? a : b); }
inline int max(int a, int b) { return (a > b ? a : b); }
char _NoteText[5]={'x','x','x','x','\0'};
char *
NoteText(int note)
{
_NoteText[0]=(" C D F G A ")[note%12];
_NoteText[1]=("C#D#EF#G#A#B")[note%12];
_NoteText[2]=("-0123456789")[note/12];
_NoteText[3]=("1 ")[note/12];
return _NoteText;
}
UBYTE *
voiceAddr(int voice)
{
/* return voice*DX7_VOICE_SIZE_PACKED+VoiceData; */
return (voice << 7) +VoiceData;
}
void
PrintVName(int voice) /* print name of voice - packed only! */
{
UBYTE ca[11];
int i;
memcpy(ca, voiceAddr(voice)+118, 10);
for (i=0; i<10; i++) {
if (ca[i] < 32)
ca[i]=183; /* centered dot */
else if (ca[i] >= 128)
ca[i]=174; /* (R) symbol = out-of-range */
else {
switch (ca[i]) {
case 92: ca[i]=165; break; /* yen */
case 126: ca[i]=187; break; /* >> */
case 127: ca[i]=171; break; /* << */
}
}
}
ca[10]=0;
cprintf("%s", ca);
}
/* ==== Init/Term Routines ==== */
UBYTE InitVoice[] = {
0x62, 0x63, 0x63, 0x5A, 0x63, 0x63, 0x63, 0x00,
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x02,
0x00, 0x62, 0x63, 0x63, 0x5A, 0x63, 0x63, 0x63,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00,
0x02, 0x00, 0x62, 0x63, 0x63, 0x5A, 0x63, 0x63,
0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x02, 0x00, 0x62, 0x63, 0x63, 0x5A, 0x63,
0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
0x00, 0x00, 0x02, 0x00, 0x62, 0x63, 0x63, 0x5A,
0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x02, 0x00, 0x62, 0x63, 0x63,
0x5A, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x00, 0x63, 0x02, 0x00, 0x63, 0x63,
0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x08,
0x23, 0x00, 0x00, 0x00, 0x31, 0x18, 0x20, 0x20,
0x20, 0x7F, 0x2D, 0x2D, 0x7E, 0x20, 0x20, 0x20 };
UBYTE InitVoiceUnpacked[155] = {
0x62, 0x63, 0x63, 0x5a, 0x63, 0x63, 0x63, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x07, 0x62, 0x63, 0x63,
0x5a, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x07, 0x62, 0x63, 0x63, 0x5a, 0x63, 0x63,
0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x62,
0x63, 0x63, 0x5a, 0x63, 0x63, 0x63, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x07, 0x62, 0x63, 0x63, 0x5a,
0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x07, 0x62, 0x63, 0x63, 0x5a, 0x63, 0x63, 0x63,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x63, 0x00, 0x01, 0x00, 0x07, 0x63, 0x63,
0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00,
0x01, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
0x18, 0x20, 0x20, 0x20, 0x7f, 0x2d, 0x2d, 0x7e,
0x20, 0x20, 0x20
};
void
EraseVoice(int voice)
{
memcpy(voiceAddr(voice), InitVoice, DX7_VOICE_SIZE_PACKED);
}
void
ConsoleTerm(void)
{
endwin();
}
bool
ConsoleInit(void)
{
initscr();
cbreak();
keypad(stdscr, TRUE);
curs_set(0);
start_color();
#if 1
init_pair(COLOR_MSG, COLOR_WHITE, COLOR_YELLOW); /* 0x1c */
init_pair(COLOR_LABEL, COLOR_GREEN, COLOR_BLUE); /* 0x1a */
init_pair(COLOR_DATA, COLOR_WHITE, COLOR_BLUE); /* 0x1f */
init_pair(COLOR_BLOCK, COLOR_WHITE, COLOR_CYAN); /* 0x3f */
init_pair(COLOR_CURSOR, COLOR_BLACK, COLOR_GREEN); /* 0x20 */
init_pair(COLOR_BCURSOR, COLOR_WHITE, COLOR_GREEN); /* 0x2f */
init_pair(COLOR_OPON, COLOR_GREEN, COLOR_BLUE); /* 0x1a */
init_pair(COLOR_OPOFF, COLOR_WHITE, COLOR_YELLOW); /* 0x14 */
#else
init_pair(COLOR_MSG, COLOR_WHITE, COLOR_YELLOW); /* 0x1c */
init_pair(COLOR_LABEL, COLOR_WHITE, COLOR_YELLOW); /* 0x1a */
init_pair(COLOR_DATA, COLOR_WHITE, COLOR_BLUE); /* 0x1f */
init_pair(COLOR_BLOCK, COLOR_BLACK, COLOR_YELLOW); /* 0x3f */
init_pair(COLOR_CURSOR, COLOR_WHITE, COLOR_YELLOW); /* 0x20 */
init_pair(COLOR_BCURSOR, COLOR_BLACK, COLOR_YELLOW); /* 0x2f */
init_pair(COLOR_OPON, COLOR_WHITE, COLOR_YELLOW); /* 0x1a */
init_pair(COLOR_OPOFF, COLOR_WHITE, COLOR_YELLOW); /* 0x14 */
#endif
bkgdset(COLOR_PAIR(COLOR_DATA));
attrset(COLOR_PAIR(COLOR_DATA)|A_BOLD);
noecho();
return TRUE;
}
void
BuffTerm(void)
{
if (Buffer) {
free(Buffer);
Buffer = NULL;
}
}
bool
BuffInit(void) /* returns TRUE if successful */
{
int i;
BuffTerm();
/* calculate buffer size from number of voices * DX7_VOICE_SIZE_PACKED plus a bulk
dump buffer and a single dump buffer */
BufferLength = Voices * DX7_VOICE_SIZE_PACKED + DX7_DUMP_SIZE_VOICE_BULK + DX7_DUMP_SIZE_VOICE_SINGLE;
if (!(Buffer = malloc(BufferLength))) {
return FALSE;
}
VoiceData = Buffer;
BulkDump = VoiceData + Voices * DX7_VOICE_SIZE_PACKED;
SingleDump = BulkDump + DX7_DUMP_SIZE_VOICE_BULK; /* must be last for alignment */
SingleData = SingleDump + 6;
/* Init the buffers */
for (i = 0; i < Voices; EraseVoice(i++));
return TRUE;
}
bool
MidiInit(void) /* returns TRUE if successful */
{
#ifdef USE_ALSA_MIDI
const char *device = "hw"; /* could also be "default" */
/* if (snd_seq_open(&MidiHandle, device, SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) { */
if (snd_seq_open(&MidiHandle, device, SND_SEQ_OPEN_OUTPUT, 0) < 0) {
fprintf(stderr, "MidiInit: could not open sequencer: %s\n", snd_strerror(errno));
return FALSE;
}
snd_seq_set_client_name (MidiHandle, "TX/Edit");
MidiClient = snd_seq_client_id(MidiHandle);
if ((MidiPort = snd_seq_create_simple_port(MidiHandle, "TX/Edit",
SND_SEQ_PORT_CAP_READ |
SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) {
fprintf(stderr, "MidiInit: error creating port: %s\n", snd_strerror(errno));
return FALSE;
}
return TRUE;
#else /* not USE_ALSA_MIDI */
return TRUE;
#endif /* USE_ALSA_MIDI */
}
void
MidiTerm(void)
{
#ifdef USE_ALSA_MIDI
if (MidiHandle) {
snd_seq_drain_output(MidiHandle); /* do we need this? could use snd_seq_drop_output(handle) */
}
if (MidiPort >= 0) {
snd_seq_delete_simple_port (MidiHandle, MidiPort);
MidiPort = -1;
}
if (MidiHandle) {
snd_seq_close(MidiHandle);
MidiHandle = NULL;
}
#endif /* USE_ALSA_MIDI */
}
void
TXTerm(int retcode)
{
ConsoleTerm();
BuffTerm();
MidiTerm();
exit(retcode);
}
void
TXInit(void) /* exit()s on failure */
{
if (!MidiInit()) {
fprintf(stderr, "MidiInit error!\n");
TXTerm(RETURN_FAIL);
}
if (!BuffInit()) {
fprintf(stderr, "Can't allocate memory for Voice Buffer!\n");
TXTerm(RETURN_FAIL);
}
if (!ConsoleInit()) {
fprintf(stderr, "ConsoleInit error!\n");
TXTerm(RETURN_FAIL);
}
}
/* ==== Console Routines ==== */
void
cprintf(const char *fmt, ...) {
va_list ap;
char tbuf[512];
va_start(ap, fmt);
(void) vsnprintf(tbuf, 512, fmt, ap);
va_end(ap);
addstr(tbuf);
}
int
cputch(int c) {
return addch(c);
}
int
cgetch(void)
{
int c = getch();
if(c == 27) {
c = getch();
if (isalpha(c)) c = tolower(c);
return 0x200 + c;
}
return c;
}
void
textattr(enum textcolor c) {
bkgdset(COLOR_PAIR(c));
attrset(COLOR_PAIR(c)|A_BOLD);
}
void
paktc(void)
{
textattr(COLOR_MSG);
cprintf(" Press Any Key to Continue... ");
textattr(COLOR_DATA);
cgetch();
cprintf("\r");
clrtoeol();
}
void
gotomsg(void)
{
move(LibRows + 4, 2);
}
/* ==== Midi Routines ==== */
void
Unpack(int voice)
{
UBYTE *a2, *a3;
UBYTE d1, d2;
a2=SingleData; /* a2 = &unpacked data */
a3=voiceAddr(voice); /* a3 = &packed data */
for (d2=6; d2>0; d2--) {
for (d1=11; d1>0; d1--) { *a2++=*a3++; } /* through rd */
*a2++=(*a3)&0x03; /* lc */
*a2++=(*a3++)>>2; /* rc */
*a2++=(*a3)&0x07; /* rs */
*(a2+6)=(*a3++)>>3; /* pd */
*a2++=(*a3)&0x03; /* ams */
*a2++=(*a3++)>>2; /* kvs */
*a2++=*a3++; /* ol */
*a2++=(*a3)&0x01; /* m */
*a2++=(*a3++)>>1; /* fc */
*a2=*a3++; /* ff */
a2+=2;
} /* operator done */
for (d2=9; d2>0; d2--) {
*a2++=*a3++;
} /* through algorithm */
*a2++=(*a3)&0x07; /* feedback */
*a2++=(*a3++)>>3; /* oks */
for (d2=4; d2>0; d2--) {
*a2++=*a3++;
} /* through lamd */
*a2++=(*a3)&0x01; /* lfo ks */
*a2++=((*a3)>>1)&0x07; /* lfo wave */
*a2++=(*a3++)>>4; /* lfo pms */
for (d2=11; d2>0; d2--) {
*a2++=*a3++;
} /* through name */
}
void
_Pack(UBYTE *packed, UBYTE *unpacked)
{
UBYTE *a2, *a3;
UBYTE d1, d2;
a3=packed; /* a3 = &packed data */
a2=unpacked; /* a2 = &unpacked data */
for (d2=6; d2>0; d2--) {
for (d1=11; d1>0; d1--) { *a3++=*a2++; } /* through rd */
*a3++=((*a2)&0x03)|(((*(a2+1))&0x03)<<2);
a2+=2; /* rc+lc */
*a3++=((*a2)&0x07)|(((*(a2+7))&0x0f)<<3);
a2++; /* pd+rs */
*a3++=((*a2)&0x03)|(((*(a2+1))&0x07)<<2);
a2+=2; /* kvs+ams */
*a3++=*a2++; /* ol */
*a3++=((*a2)&0x01)|(((*(a2+1))&0x1f)<<1);
a2+=2; /* fc+m */
*a3++=*a2;
a2+=2; /* ff */
} /* operator done */
for (d2=9; d2>0; d2--) { *a3++=*a2++; } /* through algorithm */
*a3++=((*a2)&0x07)|(((*(a2+1))&0x01)<<3);
a2+=2; /* oks+fb */
for (d2=4; d2>0; d2--) { *a3++=*a2++; } /* through lamd */
*a3++=((*a2)&0x01)|(((*(a2+1))&0x07)<<1)|
(((*(a2+2))&0x07)<<4);
a2+=3; /* lpms+lfw+lks */
for (d2=11; d2>0; d2--) { *a3++=*a2++; } /* through name */
#ifdef GAK
d2=a3-voiceAddr(voice);
cprintf("128 %d\r\n",d2);
d2=a2-SingleData;
cprintf("155 %d\r\n",d2);
getch();
#endif
}
void
Pack(int voice)
{
_Pack(voiceAddr(voice), SingleData);
}
void
PutMidiMsg(UBYTE *buf, unsigned int size)
{
#ifdef USE_ALSA_MIDI
snd_seq_event_t event;
snd_seq_ev_clear(&event);
snd_seq_ev_set_source(&event, MidiPort);
snd_seq_ev_set_subs(&event);
snd_seq_ev_set_direct(&event);
// set event type, data, so on:
event.type = SND_SEQ_EVENT_SYSEX;
snd_seq_ev_set_variable(&event, size, buf);
if (snd_seq_event_output(MidiHandle, &event) < 0) {
gotomsg();
cprintf("PutMidiMsg: could not write output: %s\n", snd_strerror(errno));
return;
}
if (snd_seq_drain_output(MidiHandle) < 0) {
gotomsg();
cprintf("PutMidiMsg: error draining output: %s\n", snd_strerror(errno));
}
#else /* not USE_ALSA_MIDI: */
FILE *fh;
if ((fh = fopen("/dev/midi00", "wb"))) { /* should fix this.... */
fwrite(buf, 1, size, fh);
fclose(fh);
}
#endif /* USE_ALSA_MIDI */
}
void
ChecksumSingle(void)
{
int sum = 0;
int i;
for (i = 0; i < DX7_VOICE_SIZE_UNPACKED; sum -= SingleData[i++]);
SingleData[DX7_VOICE_SIZE_UNPACKED] = sum & 0x7F;
}
void
PutUnpacked(void)
{
UBYTE *sd;
ChecksumSingle();
sd = SingleDump;
sd[0] = 0xF0;
sd[1] = 0x43;
sd[2] = TXChannel;
sd[3] = 0;
sd[4] = 0x01;
sd[5] = 0x1B;
sd[DX7_DUMP_SIZE_VOICE_SINGLE - 1] = 0xF7;
PutMidiMsg(sd, DX7_DUMP_SIZE_VOICE_SINGLE);
}
void
PutPacked(int voice)
{
Unpack(voice);
PutUnpacked();
}
void
PutBank(int voice)
{
UBYTE *bd = BulkDump,
*p1 = voiceAddr(voice),
*p2,
*pe,
chksum = 0;
if(voice <= Voices - 32) {
bd[0] = 0xF0;
bd[1] = 0x43;
bd[2] = TXChannel;
bd[3] = 9;
bd[4] = 0x10;
bd[5] = 0x00;
for(p2 = bd + 6, pe = p2 + 4096; p2 < pe; chksum -= *p2++ = *p1++);
bd[DX7_DUMP_SIZE_VOICE_BULK - 2] = chksum & 0x7f;
bd[DX7_DUMP_SIZE_VOICE_BULK - 1] = 0xF7;
PutMidiMsg(bd, DX7_DUMP_SIZE_VOICE_BULK);
} else {
beep();
}
}
void
PutParm(int parm)
{
UBYTE offset = veParm[parm].Offset;
UBYTE bd[7];
bd[0] = 0xF0;
bd[1] = 0x43;
bd[2] = 0x10 | TXChannel;
bd[3] = offset >> 7;
bd[4] = offset & 0x7F;
bd[5] = SingleData[offset];
bd[6] = 0xF7;
PutMidiMsg(bd, 7);
}
/* ==== Load/Save Routines ==== */
bool
FileRequest(char *namebuf, char *title)
{
echo(); curs_set(1);
cprintf(" %s\n\n Enter filename:\n > ",title);
refresh();
if (wgetnstr(stdscr, namebuf, 76) == ERR) {
namebuf[0] = 0;
}
noecho(); curs_set(0);
cprintf("\n");
return (strlen(namebuf)!=0);
}
void
LoadError(const char *filename, const char *error)
{
cprintf(" Load - Error reading file '%s':\n", filename);
cprintf(" '%s'!\n", error);
paktc();
}
int
Load(char *filename)
{
FILE *fp;
char errbuf[256];
long filelength;
unsigned char *raw_patch_data = NULL;
size_t filename_length;
int count;
int patchstart;
int midshift;
int datastart;
int i;
int op;
/* this needs to 1) open and parse the file, 2a) if it's good, copy as
* many patches as will fit into VoiceData beginning at Voice_Cursor,
* 2b) if it's not good, print an appropriate error message and return. */
if ((fp = fopen(filename, "rb")) == NULL) {
snprintf(errbuf, 256, "could not open file for reading: %s", strerror(errno));
LoadError(filename, errbuf);
return 0;
}
if (fseek(fp, 0, SEEK_END) ||
(filelength = ftell(fp)) == -1 ||
fseek(fp, 0, SEEK_SET)) {
snprintf(errbuf, 256, "couldn't get length of patch file: %s", strerror(errno));
fclose(fp);
LoadError(filename, errbuf);
return 0;
}
if (filelength == 0) {
fclose(fp);
LoadError(filename, "patch file has zero length");
return 0;
} else if (filelength > 2097152) {
fclose(fp);
LoadError(filename, "patch file is too large");
return 0;
} else if (filelength < DX7_VOICE_SIZE_PACKED) {
fclose (fp);
LoadError(filename, "patch file is too small");
return 0;
}
if (!(raw_patch_data = (unsigned char *)malloc(filelength))) {
fclose(fp);
LoadError(filename, "couldn't allocate memory for raw patch file");
return 0;
}
if (fread(raw_patch_data, 1, filelength, fp) != (size_t)filelength) {
snprintf(errbuf, 256, "short read on patch file: %s", strerror(errno));
free(raw_patch_data);
fclose(fp);
LoadError(filename, errbuf);
return 0;
}
fclose(fp);
filename_length = strlen (filename);
/* check if the file is a standard MIDI file */
if (raw_patch_data[0] == 0x4d && /* "M" */
raw_patch_data[1] == 0x54 && /* "T" */
raw_patch_data[2] == 0x68 && /* "h" */
raw_patch_data[3] == 0x64) /* "d" */
midshift = 2;
else
midshift = 0;
/* scan SysEx or MIDI file for SysEx header(s) */
count = 0;
datastart = 0;
for (patchstart = 0; patchstart + midshift + 5 < filelength; patchstart++) {
if (raw_patch_data[patchstart] == 0xf0 &&
raw_patch_data[patchstart + 1 + midshift] == 0x43 &&
raw_patch_data[patchstart + 2 + midshift] <= 0x0f &&
raw_patch_data[patchstart + 3 + midshift] == 0x09 &&
raw_patch_data[patchstart + 5 + midshift] == 0x00 &&
patchstart + 4103 + midshift < filelength &&
raw_patch_data[patchstart + 4103 + midshift] == 0xf7) { /* DX7 32 voice dump */
memmove(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
raw_patch_data + patchstart + 6 + midshift, 4096);
count += 32;
patchstart += 4104;
} else if (raw_patch_data[patchstart] == 0xf0 &&
raw_patch_data[patchstart + midshift + 1] == 0x43 &&
raw_patch_data[patchstart + midshift + 2] <= 0x0f &&
raw_patch_data[patchstart + midshift + 4] == 0x01 &&
raw_patch_data[patchstart + midshift + 5] == 0x1b &&
patchstart + midshift + 162 < filelength &&
raw_patch_data[patchstart + midshift + 162] == 0xf7) { /* DX7 single voice (edit buffer) dump */
_Pack ((UBYTE *)errbuf, /* pack to errbuf to avoid a collision */
raw_patch_data + patchstart + midshift + 6);
memcpy(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
errbuf, DX7_VOICE_SIZE_PACKED);
count += 1;
patchstart += DX7_DUMP_SIZE_VOICE_SINGLE;
}
}
/* assume raw DX7/TX7 data if no SysEx header was found. */
/* assume the user knows what she is doing ;-) */
if (count == 0)
count = filelength / DX7_VOICE_SIZE_PACKED;
/* Dr.T and Steinberg TX7 file needs special treatment */
if ((!strcmp(filename + filename_length - 4, ".TX7") ||
!strcmp(filename + filename_length -4, ".SND") ||
!strcmp(filename + filename_length -4, ".tx7") ||
!strcmp(filename + filename_length - 4, ".snd")) && filelength == 8192) {
count = 32;
filelength = 4096;
}
/* Transform XSyn file also needs special treatment */
if ((!strcmp(filename + filename_length - 4, ".BNK") ||
!strcmp(filename + filename_length - 4, ".bnk")) && filelength == 8192) {
for (i=0; i<32; i++)
{
memmove(raw_patch_data + 128*i, raw_patch_data + 256*i, 128);
}
count = 32;
filelength = 4096;
}
/* Steinberg Synthworks DX7 SND */
if ((!strcmp (filename + filename_length - 4, ".SND") ||
!strcmp (filename + filename_length - 4, ".snd")) && filelength == 5216) {
count = 32;
filelength = 4096;
}
/* Voyetra SIDEMAN DX/TX
* Voyetra Patchmaster DX7/TX7 */
if ((filelength == 9816 || filelength == 5663) &&
raw_patch_data[0] == 0xdf &&
raw_patch_data[1] == 0x05 &&
raw_patch_data[2] == 0x01 && raw_patch_data[3] == 0x00) {
count = 32;
datastart = 0x60f;
}
/* Yamaha DX200 editor .DX2 file */
if ((!strcmp (filename + filename_length - 4, ".DX2") ||
!strcmp (filename + filename_length - 4, ".dx2"))
&& filelength == 326454)
{
memmove (raw_patch_data + 16384, raw_patch_data + 34, 128 * 381);
for (count = 0; count < 128; count++)
{
for (op = 0; op < 6; op++)
{
for (i = 0; i < 8; i++)
{
raw_patch_data[17 * (5 - op) + i + 128 * count] =
raw_patch_data[16384 + 35 * op + 76 + i + 381 * count];
}
raw_patch_data[17 * (5 - op) + 8 + 128 * count] =
raw_patch_data[16384 + 35 * op + 84 + 381 * count] - 21;
raw_patch_data[17 * (5 - op) + 9 + 128 * count] =
raw_patch_data[16384 + 35 * op + 87 + 381 * count];
raw_patch_data[17 * (5 - op) + 10 + 128 * count] =
raw_patch_data[16384 + 35 * op + 88 + 381 * count];
raw_patch_data[17 * (5 - op) + 11 + 128 * count] =
raw_patch_data[16384 + 35 * op + 85 + 381 * count] +
raw_patch_data[16384 + 35 * op + 86 + 381 * count] * 4;
raw_patch_data[17 * (5 - op) + 12 + 128 * count] =
raw_patch_data[16384 + 35 * op + 89 + 381 * count] +
raw_patch_data[16384 + 35 * op + 75 + 381 * count] * 8;
if (raw_patch_data[16384 + 35 * op + 71 + 381 * count] > 3)
raw_patch_data[16384 + 35 * op + 71 + 381 * count] = 3;
raw_patch_data[17 * (5 - op) + 13 + 128 * count] =
raw_patch_data[16384 + 35 * op + 71 + 381 * count] / 2 +
raw_patch_data[16384 + 35 * op + 91 + 381 * count] * 4;
raw_patch_data[17 * (5 - op) + 14 + 128 * count] =
raw_patch_data[16384 + 35 * op + 90 + 381 * count];
raw_patch_data[17 * (5 - op) + 15 + 128 * count] =
raw_patch_data[16384 + 35 * op + 72 + 381 * count] +
raw_patch_data[16384 + 35 * op + 73 + 381 * count] * 2;
raw_patch_data[17 * (5 - op) + 16 + 128 * count] =
raw_patch_data[16384 + 35 * op + 74 + 381 * count];
}
for (i = 0; i < 4; i++)
{
raw_patch_data[102 + i + 128 * count] =
raw_patch_data[16384 + 26 + i + 381 * count];
}
for (i = 0; i < 4; i++)
{
raw_patch_data[106 + i + 128 * count] =
raw_patch_data[16384 + 32 + i + 381 * count];
}
raw_patch_data[110 + 128 * count] =
raw_patch_data[16384 + 17 + 381 * count];
raw_patch_data[111 + 128 * count] =
raw_patch_data[16384 + 18 + 381 * count] +
raw_patch_data[16384 + 38 + 381 * count] * 8;
for (i = 0; i < 4; i++)
{
raw_patch_data[112 + i + 128 * count] =
raw_patch_data[16384 + 20 + i + 381 * count];
}
raw_patch_data[116 + 128 * count] =
raw_patch_data[16384 + 24 + 381 * count] +
raw_patch_data[16384 + 19 + 381 * count] * 2 +
raw_patch_data[16384 + 25 + 381 * count] * 16;
raw_patch_data[117 + 128 * count] =
raw_patch_data[16384 + 37 + 381 * count] - 36;
for (i = 0; i < 10; i++)
{
raw_patch_data[118 + i + 128 * count] =
raw_patch_data[16384 + i + 381 * count];
}
}
count = 128;
filelength = 16384;
datastart = 0;
}
/* finally, copy patchdata to the right location */
if (count > Voices - Voice_Cursor) { /* if ( voices-in-file > voices-to-end-of-buffer ) */
cprintf(" Load - Patch file '%s' too big for remaining space:\n", filename);
cprintf(" %d patches in file, only %d loaded!\n", count, Voices - Voice_Cursor);
paktc();
count = Voices - Voice_Cursor;
}
memcpy(voiceAddr(Voice_Cursor), raw_patch_data + datastart, DX7_VOICE_SIZE_PACKED * count);
free (raw_patch_data);
cprintf(" File '%s' loaded.\n", filename);
return count;
}
void
Save(int vstart, int vend) /* range is inclusive, filename in FNameBuff */
{
FILE *fh;
long flength;
if ((fh = fopen(FNameBuff, "wb")) != 0) {
flength = (vend - vstart + 1) * DX7_VOICE_SIZE_PACKED;
if (flength != fwrite(voiceAddr(vstart), 1, flength, fh)) {
cprintf("Save - Error writing file '%s':\n", FNameBuff);
cprintf(" '%s'!\n", strerror(errno));
paktc();
}
fclose(fh);
} else {
cprintf("Save - Error opening file '%s':\n", FNameBuff);
cprintf(" '%s'!\n", strerror(errno));
paktc();
}
}
/* ==== VoiceEdit Stuff ==== */
void
ve_ShowAlg(void)
{
int alg = SingleData[134],
x,
y;
char *s = veAlg[alg];
bool t;
textattr(COLOR_LABEL);
for (y = 12; y <= 20; y++) {
x = 56;
move(y, x);
for (; x <= 72; x++) {
switch (*s) {
case '1': t = (!!(ve_OpSelect&32)); goto printop;
case '2': t = (!!(ve_OpSelect&16)); goto printop;
case '3': t = (!!(ve_OpSelect& 8)); goto printop;
case '4': t = (!!(ve_OpSelect& 4)); goto printop;
case '5': t = (!!(ve_OpSelect& 2)); goto printop;
case '6': t = (!!(ve_OpSelect& 1));
printop:
textattr(t ? COLOR_OPON : COLOR_OPOFF);
cputch(*s++);
textattr(COLOR_LABEL);
break;
case 0:
cputch(' ');
break;
case '\n':
cputch(' ');
if (x == 72) s++;
break;
case '^':
cputch(ACS_BTEE); s++;
break;
case '-':
cputch(ACS_HLINE); s++;
break;
case 'L':
cputch(ACS_LLCORNER); s++;
break;
case '/':
cputch(ACS_LRCORNER); s++;
break;
case '}':
cputch(ACS_LTEE); s++;
break;
case '+':
cputch(ACS_PLUS); s++;
break;
#if 0
case '?': /* -FIX- */
cputch(ACS_RTEE); s++;
break;
case '?': /* -FIX- */
cputch(ACS_TTEE); s++;
break;
#endif
case '\'':
cputch(ACS_ULCORNER); s++;
break;
case '`':
cputch(ACS_URCORNER); s++;
break;
case '|':
cputch(ACS_VLINE); s++;
break;
default:
cputch(*s++);
break;
}
}
}
textattr(COLOR_DATA);
}
void
ve_FExtend(UBYTE fc, UBYTE ff, UBYTE mode, UBYTE y)
{
unsigned long f;
char ca[10];
textattr(COLOR_LABEL);
move(y, 47);
if (mode) { /* fixed */
f = veFFF[ff];
switch (fc & 3) {
case 1: f *= 10; break;
case 2: f *= 100; break;
case 3: f *= 1000; break;
}
} else {
f = fc * 10;
if (!f) f = 5;
f = (100 + ff) * f;
}
f = sprintf(ca, "%ld", f);
switch (f) {
case 3: cprintf("0.%.3s", ca); break;
case 4: cprintf("%.1s.%.3s", ca, ca + 1); break;
case 5: cprintf("%.2s.%.2s", ca, ca + 2); break;
case 6: cprintf("%.3s.%.1s", ca, ca + 3); break;
case 7: cprintf("%.4s.", ca); break;
}
textattr(COLOR_DATA);
}
void
ve_printParm(int parm)
{
unsigned char val = SingleData[veParm[parm].Offset],
c;
char *t;
move(veParm[parm].Y, veParm[parm].X);
if (parm == ve_Cursor) textattr(COLOR_CURSOR);
switch (veParm[parm].Type) {
case vptName:
{
UBYTE ca[11];
memcpy(ca, SingleData + 145, 10);
for (c = 0; c < 10; c++) {
if (ca[c] < 32)
ca[c]=183; /* centered dot */
else if (ca[c] >= 128)
ca[c]=174; /* (R) symbol = out-of-range */
else {
switch (ca[c]) {
case 92: ca[c]=165; break; /* yen */
case 126: ca[c]=187; break; /* >> */
case 127: ca[c]=171; break; /* << */
}
}
}
ca[10] = 0;
cprintf("%s", ca);
}
break;
case vpt0_99:
if (val > 99)
cprintf("??");
else
cprintf("%2.2d", val);
break;
case vpt0_7:
if (val > 7)
cputch('?');
else
cputch(val+'0');
break;
case vptMode:
switch (val) {
case 0: c = 'R'; break;
case 1: c = 'F'; break;
default: c = '?'; break;
}
cputch(c);
ve_FExtend(SingleData[veParm[parm+1].Offset],
SingleData[veParm[parm+2].Offset],
val,
veParm[parm].Y);
break;
case vptFC:
if (val > 31)
cprintf("??");
else
cprintf("%2d", val);
ve_FExtend(val,
SingleData[veParm[parm+1].Offset],
SingleData[veParm[parm-1].Offset],
veParm[parm].Y);
break;
case vptFF:
if (val > 99)
cprintf("??");
else
cprintf("%2d", val);
ve_FExtend(SingleData[veParm[parm-1].Offset],
val,
SingleData[veParm[parm-2].Offset],
veParm[parm].Y);
break;
case vptDetune: /* 0-14, as -7-+7 */
if (val > 14)
cprintf("??");
else
cprintf("%+2d", val-7);
break;
case vpt0_3:
if (val > 3)
cputch('?');
else
cputch(val+'0');
break;
case vptAlg: /* 0-31, as 1-32 */
if (val > 31) {
cprintf("??");
break;
}
cprintf("%2d", val+1);
ve_ShowAlg();
return;
case vptCurve:
switch (val) {
case 0: t = "-Lin"; break;
case 1: t = "-Exp"; break;
case 2: t = "+Exp"; break;
case 3: t = "+Lin"; break;
default: t = "????";
}
cprintf("%s", t);
break;
case vptBkPt:
if (val > 99) {
cprintf("????");
break;
}
val += 21;
goto printnote;
case vptTrans:
if (val > 48) {
cprintf("????");
break;
}
val += 36;
printnote:
cprintf("%s", NoteText(val));
break;
case vptOnOff:
switch (val) {
case 0: t = "Off"; break;
case 1: t = " On"; break;
default: t = "???";
}
cprintf("%s", t);
break;
case vptWave:
switch (val) {
case 0: t = "TRI"; break;
case 1: t = "SW-"; break;
case 2: t = "SW+"; break;
case 3: t = "SQU"; break;
case 4: t = "SIN"; break;
case 5: t = "S/H"; break;
default: t = "???"; break;
}
cprintf("%s", t);
break;
}
if (parm == ve_Cursor) textattr(COLOR_DATA);
}
void
ve_SetScreen(void)
{
textattr(COLOR_DATA);
cprintf(" TX/Edit Voice Edit");
textattr(COLOR_LABEL);
cprintf(" Name\n"
" A\n"
" O R V M\n"
" P R1 L1 R2 L2 R3 L3 R4 L4 S M FC FF D Freq. OL S S\n");
cprintf(" 1\n"
" 2\n"
" 3\n"
" 4\n"
" 5\n"
" 6\n"
" P\n");
cprintf(" Alg.\n"
" Left BkPt Right Speed Fdbk\n");
cprintf(" 1 Delay C4=\n");
cprintf(" 2 PMD OKS\n");
cprintf(" 3 AMD\n");
cprintf(" 4 Sync\n");
cprintf(" 5 Wave\n");
cprintf(" 6 PMS\n");
textattr(COLOR_DATA);
}
void
ve_DoScreen(void)
{
int i;
for (i = 0; i < VOICEPARMS; ve_printParm(i++));
}
void
ve_Name(int c)
{
UBYTE i;
for(i = 145; i < 154; i++) SingleData[i] = SingleData[i + 1];
SingleData[154] = c;
PutUnpacked();
ve_printParm(0);
ve_OpSelect = 63;
ve_ShowAlg();
}
void
ve_Inc(int parm)
{
unsigned char val = SingleData[veParm[parm].Offset],
max;
max = vtypemax[veParm[parm].Type];
if (!max) return;
if (++val > max) val = 0;
SingleData[veParm[parm].Offset] = val;
PutParm(parm);
ve_printParm(parm);
}
void
ve_Dec(int parm)
{
unsigned char val = SingleData[veParm[parm].Offset],
max;
max = vtypemax[veParm[parm].Type];
if (!max) return;
if (val)
val--;
else
val = max;
SingleData[veParm[parm].Offset] = val;
PutParm(parm);
ve_printParm(parm);
}
void
ve_Zero(void)
{
UBYTE offset = veParm[ve_Cursor].Offset;
if(ve_Cursor == 0) { /* do name */
for(offset = 154; offset > 145; offset--)
SingleData[offset] = SingleData[offset - 1];
SingleData[145] = ' ';
PutUnpacked();
ve_OpSelect = 63;
ve_ShowAlg();
} else {
SingleData[offset] = InitVoiceUnpacked[offset];
PutParm(ve_Cursor);
}
ve_printParm(ve_Cursor);
}
void
ve_CurUp(void)
{
int oldcursor = ve_Cursor;
#ifndef USE_CALCED_CURSOR_MOVES
ve_Cursor = veParm[ve_Cursor].Up;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
#else /* USE_CALCED_CURSOR_MOVES */
int i, dx, dy, distance,
best = -1,
bestdistance = 1000;
/* try to find the closest parm in the 'up' direction */
for (i = 0; i <= VOICEPARMMAX; i++) {
dx = abs(veParm[ve_Cursor].X - veParm[i].X);
dy = (veParm[ve_Cursor].Y - 1) - veParm[i].Y;
if (dy < 0)
dy += VOICEPARMS_Y_SPAN + 2; /* wrap */
dy = dy * 5 / 2; /* prefer something <2.5 spaces away horizontally to 1 space vertically */
distance = dx + dy;
if (bestdistance > distance) {
bestdistance = distance;
best = i;
}
}
if (best >= 0) {
ve_Cursor = best;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
}
#endif /* USE_CALCED_CURSOR_MOVES */
}
void
ve_CurDown(void)
{
int oldcursor = ve_Cursor;
#ifndef USE_CALCED_CURSOR_MOVES
ve_Cursor = veParm[ve_Cursor].Down;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
#else /* USE_CALCED_CURSOR_MOVES */
int i, dx, dy, distance,
best = -1,
bestdistance = 1000;
/* try to find the closest parm in the 'down' direction */
for (i = 0; i <= VOICEPARMMAX; i++) {
dx = abs(veParm[i].X - veParm[ve_Cursor].X);
dy = veParm[i].Y - (veParm[ve_Cursor].Y + 1);
if (dy < 0)
dy += VOICEPARMS_Y_SPAN + 2; /* wrap */
dy = dy * 5 / 2; /* prefer something <2.5 spaces away horizontally to 1 space vertically */
distance = dx + dy;
if (bestdistance > distance) {
bestdistance = distance;
best = i;
}
}
if (best >= 0) {
ve_Cursor = best;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
}
#endif /* USE_CALCED_CURSOR_MOVES */
}
void
ve_CurRight(void)
{
int oldcursor = ve_Cursor;
#ifndef USE_CALCED_CURSOR_MOVES
if(++ve_Cursor > VOICEPARMMAX) ve_Cursor = 0;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
#else /* USE_CALCED_CURSOR_MOVES */
int i, dx, dy, distance,
best = -1,
bestdistance = 1000;
/* try to find the closest parm in the 'right' direction */
for (i = 0; i <= VOICEPARMMAX; i++) {
dx = veParm[i].X - (veParm[ve_Cursor].X + 2);
if (dx < 0)
dx += VOICEPARMS_X_SPAN + 4; /* wrap */
dy = abs(veParm[i].Y - veParm[ve_Cursor].Y);
dy = dy * 12; /* prefer something <8 spaces away horizontally to 1 space vertically */
distance = dx + dy;
if (bestdistance > distance) {
bestdistance = distance;
best = i;
}
}
if (best >= 0) {
ve_Cursor = best;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
}
#endif /* USE_CALCED_CURSOR_MOVES */
}
void
ve_CurLeft(void)
{
int oldcursor = ve_Cursor;
#ifndef USE_CALCED_CURSOR_MOVES
if(ve_Cursor)
ve_Cursor--;
else
ve_Cursor = VOICEPARMMAX;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
#else /* USE_CALCED_CURSOR_MOVES */
int i, dx, dy, distance,
best = -1,
bestdistance = 1000;
/* try to find the closest parm in the 'left' direction */
for (i = 0; i <= VOICEPARMMAX; i++) {
dx = (veParm[ve_Cursor].X - 2) - veParm[i].X;
if (dx < 0)
dx += VOICEPARMS_X_SPAN + 4; /* wrap */
dy = abs(veParm[i].Y - veParm[ve_Cursor].Y);
dy = dy * 12; /* prefer something <8 spaces away horizontally to 1 space vertically */
distance = dx + dy;
if (bestdistance > distance) {
bestdistance = distance;
best = i;
}
}
if (best >= 0) {
ve_Cursor = best;
ve_printParm(oldcursor);
ve_printParm(ve_Cursor);
}
#endif /* USE_CALCED_CURSOR_MOVES */
}
void
ve_Erase(void)
{
memcpy(SingleData, InitVoiceUnpacked, DX7_VOICE_SIZE_UNPACKED);
// erase();
// ve_SetScreen();
ve_DoScreen();
refresh();
PutUnpacked();
}
void
ve_PgUp(void)
{
if (Voice_Cursor) {
Pack(Voice_Cursor);
Unpack(--Voice_Cursor);
ve_DoScreen();
refresh();
PutUnpacked();
}
}
void
ve_PgDn(void)
{
if (Voice_Cursor < Voices - 1) {
Pack(Voice_Cursor);
Unpack(++Voice_Cursor);
ve_DoScreen();
refresh();
PutUnpacked();
}
}
void
_ve_SetOps(void)
{
UBYTE bd[7];
bd[0] = 0xF0;
bd[1] = 0x43;
bd[2] = 0x10 | TXChannel;
bd[3] = 1;
bd[4] = 27;
bd[5] = ve_OpSelect;
bd[6] = 0xF7;
PutMidiMsg(bd, 7);
}
void
ve_SetOps(int o)
{
UBYTE i;
ve_OpSelect ^= o;
for (i = 1; i < 7; i++) {
if (ve_OpSelect & (1 << (6 - i)))
textattr(COLOR_OPON);
else
textattr(COLOR_OPOFF);
move(3 + i, 2);
cprintf("%c", i + '0');
move(12 + i, 2);
cprintf("%c", i + '0');
}
/* textattr(COLOR_DATA); not needed with ve_ShowAlg() */
ve_ShowAlg();
_ve_SetOps();
}
void
ve_Number(int c)
{
unsigned char val = SingleData[veParm[ve_Cursor].Offset],
typ = veParm[ve_Cursor].Type,
max = vtypemax[typ];
switch(typ) {
case vpt0_99:
case vptFF:
val=(val * 10 + c - '0') % 100;
break;
case vptFC:
val=(val * 10 + c - '0') % 100;
for(; val > 31; val -= 10);
break;
case vpt0_7:
case vpt0_3:
val=c - '0';
if(val > max) val = max;
break;
case vptAlg:
val=((val + 1) * 10 + c - '0') % 100;
if (!val) val = 1;
for(; val > 32; val -= 10);
val--;
break;
default:
return;
}
SingleData[veParm[ve_Cursor].Offset] = val;
PutParm(ve_Cursor);
ve_printParm(ve_Cursor);
}
void
ve_Help(void)
{
erase();
cprintf(" TX/Edit v" VERSIONSTRING " Voice Edit Help\n\n");
cprintf(" Up / Down /\n"
" Right / Left - Move cursor\n\n");
cprintf(" + - Increment field\n"
" - - Decrement field\n"
" 0 through 9 - Enter data into field\n"
" Backspace - Zero/reset field\n\n");
cprintf(" A through Z - Rotate letters into name (name field only)\n\n"
" F1 through F6 - Enable/disable operators 1 through 6\n\n");
cprintf(" Meta-P - Put edit buffer as single voice\n"
" Meta-! - Erase edit buffer to init voice\n"
" PgUp / PgDn - Move to previous / next voice\n"
" Esc / Meta-L - Return to librarian mode\n\n"
" h / Meta-H - Display this help screen\n\n");
paktc();
erase();
ve_SetScreen();
ve_DoScreen();
}
void
ve_CharIn(int c)
{
if(!ve_Cursor && c>=32 && c<=127) {
ve_Name(c);
} else {
if(c >= 'A' && c <= 'Z')
c = tolower(c);
switch(c) {
case '+':
case '=': ve_Inc(ve_Cursor); break;
case '-': ve_Dec(ve_Cursor); break;
#if 0
case kc_Del:
#endif
case KEY_BACKSPACE: ve_Zero(); break;
case KEY_UP: ve_CurUp(); break;
case KEY_DOWN: ve_CurDown(); break;
case KEY_RIGHT: ve_CurRight(); break;
case KEY_LEFT: ve_CurLeft(); break;
case KEY_METAL:
case KEY_ESC: newmode=MODELIB; break;
case KEY_F(1): ve_SetOps(32); break;
case KEY_F(2): ve_SetOps(16); break;
case KEY_F(3): ve_SetOps( 8); break;
case KEY_F(4): ve_SetOps( 4); break;
case KEY_F(5): ve_SetOps( 2); break;
case KEY_F(6): ve_SetOps( 1); break;
case KEY_PPAGE: ve_PgUp(); break;
case KEY_NPAGE: ve_PgDn(); break;
case KEY_METAP: PutUnpacked(); break;
case KEY_METAEX: ve_Erase(); break;
case KEY_METAH:
case 'h': ve_Help(); break;
default:
if(c>='0' && c<='9') {
ve_Number(c);
} else {
gotomsg();
cprintf(" Type for help...");
beep();
#ifdef DEBUG
cprintf("keycode=0x%04x", c);
#endif
}
break;
}
}
}
/* ==== Librarian Stuff ==== */
void
LibPrintVName(int voice) /* print name at correct cursor position */
{
if (Voice_TOS <= voice && voice < Voice_TOS + LibNames) {
move((voice-Voice_TOS)%LibRows + 2,
(voice-Voice_TOS)/LibRows * 15 + 1);
if (voice= Voice_TOS) {
LibPrintVName(vc);
LibPrintVName(++vc);
} else {
Voice_TOS = max(Voice_TOS - LibRows, 0);
LibDoScreen();
}
}
}
void
LibCurDown(void)
{
if (Voice_Cursor < Voices - 1) {
int vc;
vc = ++Voice_Cursor;
CheckBlock();
if (vc < Voice_TOS + LibNames) {
LibPrintVName(vc);
LibPrintVName(--vc);
} else {
Voice_TOS += LibRows;
LibDoScreen();
}
}
}
void
LibCurRight(void)
{
if (Voice_Cursor < Voices - 1) {
int oldvc, newvc;
oldvc = Voice_Cursor;
Voice_Cursor = newvc = min(oldvc + LibRows, Voices - 1);
CheckBlock();
if (newvc < Voice_TOS + LibNames) {
if (blocking) {
for (; oldvc <= newvc; LibPrintVName(oldvc++));
} else {
LibPrintVName(oldvc);
LibPrintVName(newvc);
}
} else {
Voice_TOS += LibRows;
LibDoScreen();
}
}
}
void
LibCurLeft(void)
{
if (Voice_Cursor) {
int oldvc, newvc;
oldvc = Voice_Cursor;
Voice_Cursor = newvc = max(oldvc - LibRows, 0);
CheckBlock();
if (newvc >= Voice_TOS) {
if (blocking) {
for (; oldvc >= newvc; LibPrintVName(oldvc--));
} else {
LibPrintVName(oldvc);
LibPrintVName(newvc);
}
} else {
Voice_TOS = max(Voice_TOS - LibRows, 0);
LibDoScreen();
}
}
}
void
LibCtrlPgUp(void)
{
if (Voice_Cursor) {
int oldvc, newvc;
oldvc = Voice_Cursor;
Voice_Cursor = newvc = max(Voice_Cursor - 1, 0) & 0xffe0;
CheckBlock();
if (newvc >= Voice_TOS) {
if (blocking) {
for (; oldvc >= newvc; LibPrintVName(oldvc--));
} else {
LibPrintVName(oldvc);
LibPrintVName(newvc);
}
} else {
Voice_TOS=newvc;
LibDoScreen();
}
}
}
void
LibCtrlPgDn(void)
{
if (Voice_Cursor < Voices-1) {
int oldvc, newvc;
oldvc = Voice_Cursor;
Voice_Cursor = newvc = min(((Voice_Cursor + 33) & 0xffe0) - 1, Voices - 1);
CheckBlock();
if (newvc < Voice_TOS + LibNames) {
if (blocking) {
for (; oldvc <= newvc; LibPrintVName(oldvc++));
} else {
LibPrintVName(oldvc);
LibPrintVName(newvc);
}
} else {
Voice_TOS=max(newvc - LibNames + 1, 0);
LibDoScreen();
}
}
}
void
LibCurEnd(void)
{
Voice_Cursor = Voices - 1;
Voice_TOS = max(Voices - LibNames, 0);
CheckBlock();
LibDoScreen();
}
void
LibCurHome(void)
{
Voice_Cursor = 0;
Voice_TOS = 0;
CheckBlock();
LibDoScreen();
}
void
LibPgUp(void)
{
if (Voice_Cursor) {
int oldvc, newvc;
oldvc = Voice_Cursor;
Voice_Cursor = newvc = max(Voice_Cursor - 1, 0) & 0xfff0;
CheckBlock();
if (newvc >= Voice_TOS) {
if (blocking) {
for (; oldvc >= newvc; LibPrintVName(oldvc--));
} else {
LibPrintVName(oldvc);
LibPrintVName(newvc);
}
} else {
Voice_TOS = newvc;
LibDoScreen();
}
}
}
void
LibPgDn(void)
{
if (Voice_Cursor < Voices-1) {
int oldvc, newvc;
oldvc = Voice_Cursor;
Voice_Cursor = newvc = min(((Voice_Cursor + 17) & 0xfff0) - 1, Voices - 1);
CheckBlock();
if (newvc < Voice_TOS + LibNames) {
if (blocking) {
for (; oldvc <= newvc; LibPrintVName(oldvc++));
} else {
LibPrintVName(oldvc);
LibPrintVName(newvc);
}
} else {
Voice_TOS = max(newvc - LibNames + 1, 0);
LibDoScreen();
}
}
}
void
LibCtrlRight(void)
{
Voice_Cursor = min(Voice_Cursor + LibNames, Voices - 1);
Voice_TOS = min(Voice_TOS + LibNames, max(Voices - LibNames, 0));
CheckBlock();
LibDoScreen();
}
void
LibCtrlLeft(void)
{
if (Voice_Cursor) {
Voice_Cursor = max(Voice_Cursor - LibNames, 0);
Voice_TOS = max(Voice_TOS - LibNames, 0);
CheckBlock();
LibDoScreen();
}
}
void
LBA_Copy(void)
{
#ifdef DEBUG
if (!blocked) { cprintf("LBA_Copy - not Blocked?!"); return; }
#endif
memmove(voiceAddr(Voice_Cursor),
voiceAddr(Voice_BStart),
min(Voice_BEnd - Voice_BStart + 1, Voices - Voice_Cursor) * DX7_VOICE_SIZE_PACKED);
CancelBlock();
}
void
LibCopy(void)
{
SetBlock();
EndBlock();
LibBlockAction = LBA_Copy;
gotomsg();
cprintf("Move Cursor to Copy destination and press return...");
}
void
LibDelete(void)
{
int i;
SetBlock();
if (Voices > Voice_BEnd + 1)
memmove(voiceAddr(Voice_BStart),
voiceAddr(Voice_BEnd + 1),
(Voices - Voice_BEnd - 1) * DX7_VOICE_SIZE_PACKED);
for (i = Voices - Voice_BEnd + Voice_BStart - 1; i < Voices; EraseVoice(i++));
CancelBlock();
}
void
LibErase(void)
{
int i;
SetBlock();
for (i = Voice_BStart; i <= Voice_BEnd; EraseVoice(i++));
CancelBlock();
}
void
LibLoad(void)
{
erase();
LibSetScreen();
cprintf("\n\n");
if (FileRequest(FNameBuff, "TX/Edit Load Voices")) {
Load(FNameBuff);
}
erase();
LibSetScreen();
LibDoScreen();
}
void
LBA_Move(void) /* swap patches, overlapping ranges CF! */
{
int i;
UBYTE *v1, *v2;
#ifdef DEBUG
if (!blocked) { cprintf("LBA_Move - not Blocked?!"); return; }
#endif
for (i = Voice_BStart;
(i <= Voice_BEnd) && (Voice_Cursor + i - Voice_BStart < Voices); i++) {
v1=voiceAddr(i);
v2=voiceAddr(Voice_Cursor + i - Voice_BStart);
memmove(SingleData, v1, DX7_VOICE_SIZE_PACKED);
memmove(v1, v2, DX7_VOICE_SIZE_PACKED);
memmove(v2, SingleData, DX7_VOICE_SIZE_PACKED);
}
CancelBlock();
}
void
LibMove(void)
{
SetBlock();
EndBlock();
LibBlockAction = LBA_Move;
gotomsg();
cprintf("Move Cursor to Move destination and press return...");
}
void
LibSave(void)
{
if (blocking) {
erase();
LibSetScreen();
cprintf("\n\n");
Save(Voice_BStart, Voice_BEnd);
erase();
LibSetScreen();
CancelBlock();
} else {
gotomsg();
textattr(COLOR_MSG);
cprintf(" Save - Must mark block first! - ");
paktc();
}
}
void
LibSaveAs(void)
{
if (blocking) {
erase();
LibSetScreen();
cprintf("\n\n");
if (FileRequest(FNameBuff, "TX/Edit Save Voices")) {
Save(Voice_BStart, Voice_BEnd);
}
erase();
LibSetScreen();
CancelBlock();
} else {
gotomsg();
textattr(COLOR_MSG);
cprintf("Save As - Must mark block first! - ");
paktc();
}
}
UBYTE
lstol(UBYTE c)
{
if (c >= 'A' && c <= 'Z')
return c + 32;
else
return c;
}
int
_LibSortCmp(const UBYTE *v1, const UBYTE *v2)
{
int i;
for (i = 118; i < 128; i++) {
if (lstol(v1[i]) != lstol(v2[i]))
return lstol(v1[i]) - lstol(v2[i]);
}
return 0;
}
void
LibSort(void)
{
SetBlock();
if (Voice_BStart != Voice_BEnd) {
qsort(voiceAddr(Voice_BStart), Voice_BEnd - Voice_BStart + 1,
DX7_VOICE_SIZE_PACKED, (int (*)())_LibSortCmp);
}
CancelBlock();
}
int
_LibSortCmpPatch(const UBYTE *v1, const UBYTE *v2)
{
int i;
#define SORT_BY_ALGORITHM_FIRST
#ifdef SORT_BY_ALGORITHM_FIRST
if (v1[110] != v2[110]) return v1[110] - v2[110];
#endif
for (i = 0; i < 118; i++) {
if (v1[i] != v2[i])
return v1[i] - v2[i];
}
return 0;
}
void
LibSortPatch(void)
{
SetBlock();
if (Voice_BStart != Voice_BEnd) {
qsort(voiceAddr(Voice_BStart), Voice_BEnd - Voice_BStart + 1,
DX7_VOICE_SIZE_PACKED, (int (*)())_LibSortCmpPatch);
}
/* #define SORT_PATCH_ERASE_DUPLICATES */
#ifdef SORT_PATCH_ERASE_DUPLICATES
{
int i;
for (i = Voice_BEnd - 1; i >= Voice_BStart; i--) {
if (memcmp(voiceAddr(i), voiceAddr(i + 1), 118) == 0)
EraseVoice(i + 1);
}
}
#endif
CancelBlock();
}
void
LibHelp(void)
{
erase();
cprintf(" TX/Edit v" VERSIONSTRING " Help\n\n");
cprintf(" a / Meta-A - Save block As\n"
" b / Meta-B - Start block\n"
" c / Meta-C - Copy\n"
" Meta-D - Delete\n"
" e / Meta-E - Enter Edit mode\n");
#if 0
" g / Meta-G - Get (voice or 32 voices?)\n"
#endif
cprintf(" h / Meta-H - Display this help screen\n\n"
" m / Meta-M - Move\n"
" o / Meta-O - Load\n"
" p / Meta-P - Put single voice (use space to step-send)\n");
#if 0
" r / Meta-R - Receive (voice or 32 voices?)\n"
#endif
cprintf(" Meta-S - Save block\n"
" Meta-T - Put bank (32 voices starting at cursor)\n"
" Meta-= - Sort block by patch names\n"
" Meta-+ - Sort block by patch data\n"
" Meta-! - Erase voice\n");
#if 0
" Meta-# - Change MIDI channel\n"
#endif
cprintf(" Escape - Cancel block\n"
" Enter - Perform pending block action\n"
" Up / Down /\n"
" Right / Left /\n"
" PgUp / PgDn - Move cursor\n");
#if 0
/* Ctrl-Right, Ctrl-Left, Ctrl-PgUp, Ctrl-PgDn, End, Ctrl-End, Home, Ctrl-Home could have functions */
#endif
paktc();
erase();
LibSetScreen();
LibDoScreen();
}
void
vl_CharIn(int c)
{
if(c >= 'A' && c <= 'Z')
c = tolower(c);
switch (c) {
case KEY_METAA:
case 'a': LibSaveAs(); break;
case KEY_METAB:
case 'b': StartBlock(); break;
case KEY_METAC:
case 'c': LibCopy(); break;
case KEY_METAD: LibDelete(); break;
case KEY_METAE:
case 'e': newmode=MODEEDIT; break;
#if 0
case KEY_METAG:
case 'g': cprintf("Get!!!!"); break;
#endif
case KEY_METAH:
case 'h': LibHelp(); break;
case KEY_METAM:
case 'm': LibMove(); break;
case KEY_METAO:
case 'o': LibLoad(); break;
/* Space for Step-Send */
case ' ': LibCurDown(); /* and fall through to: */
case KEY_METAP:
case 'p': PutPacked(Voice_Cursor); break;
#if 0
case KEY_METAR:
case 'r': cprintf("Receive!!!!"); break;
#endif
case KEY_METAS: LibSave(); break;
case KEY_METAT: PutBank(Voice_Cursor); break;
case KEY_METAEQ: LibSort(); break;
case KEY_METAPL: LibSortPatch(); break;
case KEY_METAEX: LibErase(); break;
#if 0
case KEY_METANU:
case '#': cprintf("Channel!!!!"); break;
#endif
case KEY_ESC: EscBlock(); break;
case KEY_ENTER: LibBlockAction(); break;
case KEY_UP: LibCurUp(); break;
case KEY_DOWN: LibCurDown(); break;
case KEY_RIGHT: LibCurRight(); break;
case KEY_LEFT: LibCurLeft(); break;
#if 0
case kc_CtrlRight: LibCtrlRight(); break;
case kc_CtrlLeft: LibCtrlLeft(); break;
#endif
case KEY_PPAGE: LibPgUp(); break;
case KEY_NPAGE: LibPgDn(); break;
#if 0
case kc_CtrlPgUp: LibCtrlPgUp(); break;
case kc_CtrlPgDn: LibCtrlPgDn(); break;
case kc_End:
case kc_CtrlEnd: LibCurEnd(); break;
case kc_Home:
case kc_CtrlHome: LibCurHome(); break;
#endif
default:
gotomsg();
cprintf(" Type for help...");
beep();
#ifdef DEBUG
cprintf("keycode=0x%04x, 0%o", c, c);
#endif
}
}
/* ==== Control ==== */
void
TXsetmode(void)
{
/* cleanup from old mode */
switch(txmode) {
case MODELIB:
blocking = FALSE;
blocked = FALSE;
LibBlockAction = noop;
break;
case MODEEDIT:
if(ve_OpSelect != 63) {
ve_OpSelect = 63;
_ve_SetOps();
}
Pack(Voice_Cursor);
break;
}
txmode=newmode;
/* set up for new mode */
switch(txmode) {
case MODELIB:
if (Voice_Cursor < Voice_TOS || Voice_Cursor >= Voice_TOS + LibNames) {
Voice_TOS = min(Voice_Cursor & 0xfff0, max(Voices - LibNames, 0));
}
erase();
LibSetScreen();
LibDoScreen();
refresh();
break;
case MODEEDIT:
erase();
Unpack(Voice_Cursor);
ve_SetScreen();
ve_DoScreen();
refresh();
PutUnpacked();
break;
}
}
int
main(int argc, char ** argv)
{
int c;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"voices", 1, 0, 'v'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "hv:", long_options, NULL)) != EOF) {
switch (c) {
case 'v':
Voices = atoi(optarg);
if (Voices < 32) Voices = 32;
break;
case 'h':
default:
fprintf(stderr, "TX/Edit v" VERSIONSTRING " (c)2004 Sean Bolton\n"
"options:\n"
"-vnnn --voices=nnn allocate nnn voice slots\n"
"-h --help print this message and exit\n");
exit(c == 'h' ? 0 : 1);
}
}
TXInit();
if (optind < argc) { /* load command line arguments */
scrollok(stdscr, TRUE);
erase();
LibSetScreen();
cprintf("\n\n");
for (c = optind; c < argc; c++) {
Voice_Cursor += Load(argv[c]);
}
paktc();
Voice_Cursor = 0;
scrollok(stdscr, FALSE);
}
newmode=MODELIB;
TXsetmode();
do {
refresh(); /* -FIX- */
c = cgetch();
switch (c) {
case KEY_METAQ: newmode=MODEQUIT; break;
default:
switch(txmode) {
case MODELIB: vl_CharIn(c); break;
case MODEEDIT: ve_CharIn(c); break;
}
break;
}
if (txmode != newmode) TXsetmode();
} while (txmode != MODEQUIT);
TXTerm(RETURN_OK); /* never returns */
return 0;
}
hexter-1.0.2/extra/tx7_roms.dx7 0000644 0000764 0000764 00000020000 11757612664 013302 0000000 0000000 ^ *c\ p: H *c\ T LH( @+cX WFM A
+cX 3 _ 3M B=@7cR ` 9PWF.cO >c cccc1222# ACC. PIANOc. +c]W 6 c 9 G c. +c]W 6 c ) M
c. .c]W 6 IT
.!+c\T Rc c. ,c]W 6 iT
.!.c\T Jc ^C_<2222&! (HI STRINGS*8Fc ?c02c== 5 2BL2c== =J )2c__ =Q c2U D `-F7c_5 bc cC_<1324"- TRUMPET AcPccc > P S 0P6ccc + c <2cca H O (P4ccc ! 8 N+/2cca cc C
/P4ccc !cc P [ KPK<2222#!$&(MALE CHOIR_2c_ ) sO _2c_ c _2c_ ;Y _2c_ ;c _2#NcK ;K"6`CcK Sc cccc2222! (ELEC.PNO AcTZc p cc6ZcKc p @ c;cZcFF p c cP6Rccc Xc2cZcca
@c cPZccc 8c cccc2222( E.ORGAN A