BeeBMIDI (Part 8)
Jay Chapman goes through the rest of the functions our own DX editing program, DX7ED, is capable of executing.
The second of a two-part look at DX7ED, E&MM's own editing program for the Yamaha DX7 and BBC Micro.
What you're about to read (or at least, I hope you are) is a discussion of the DX7ED screen 'pages' and related facilities not covered last month, followed by an explanation of some of the program's procedures. Listings of these procedures are included at strategic points along the way, but the program as a whole is too large to list in full - there has to be some space left in the magazine for other things, after all.
Figure 1 shows the Main Menu page that appears when the program is first run or whenever one of the major pages is exited. The pages for the LFO, Modulation Controllers, Algorithm Selection and Envelopes were discussed last month.
On selecting the Operator page, you'll come to an intermediate page which shows a diagram of the current algorithm with the current Operator highlighted - this is similar to the display in the centre of the Copy page in Figure 4, in which Operator 4 is highlighted. You can then change the currently-selected Operator.
The current Operator is used by default whenever an Operator-related action is required, so that manipulating Operator parameters on different pages (Operators, Envelopes, Scaling and Copy) affects the same Operator automatically. Once the current Operator has been selected, you can exit back to the main menu or move on to edit the selected Operator's parameters (except envelope and scaling parameters, which each appear on separate specialised pages). The Operator editing page is shown in Figure 2.
The Coarse and Fine pitch parameters result in a Ratio or Fixed pitch display dependent on the Mode setting at the bottom right of the page. In Ratio mode, one more digit is displayed on screen than is displayed on the DX7 itself, so that Ratios such as 0.500 and 0.505, which would both display as 0.50 on the DX, can be seen to be distinct from each other. Note that the Detune bar graphic gives a helpful visual indication of the amount and direction of the detuning taking place.
The Keyboard Scaling page (Figure 3) should help quite a few DX users come to terms with both Level and Rate scaling. The vertical axis of the Level Scaling Curve graphs - rising from the C2 key on the 'DX7 keyboard' shown on the sample page - shows where the Break Point is for level scaling. If the Break Point parameter is edited, then this axis, along with the Left and Right Curves drawn on the page, move so that the Break Point and Curves are positioned correctly with respect to the keyboard image. If the Left or Right Depths or Curve types (-LIN, -EXP, +LIN, +EXP) are altered, then the new curves are drawn on screen immediately. You can't get better feedback than that.
In the sample page shown in Figure 3, the effective level of Operator 6 will increase quite quickly below C2 (Left Curve = +LIN), and will fall to nothing with increasing speed from about F3 to the top of the DX7's keyboard (Right Curve = -EXP), as can be seen from the curves shown explicitly on the screen - or in this case, printed with widely-spaced dots. The other dotted line represents the effect of the Keyboard Rate Scaling parameter: the slope of this line corresponds to the severity of the Rate Scaling at any one time.
The Copy page (Figure 4) corresponds to, but is more powerful than, the Envelope Copy facility available on the DX7 itself. Not unexpectedly, this facility allows you to copy one envelope to another, and both source and destination envelopes are selected with reference to the diagram of the current algorithm.
It's also possible to swap two envelopes, or even to copy/swap all the parameters of any two Operators. If you can't quite imagine just how mind-blowingly useful this facility could be, here's an example. Let's say you'd set up Operators 1 - 4 as the basis for a new voice and then decided you needed to modulate Operator 2. With DX7ED, all you have to do is swap OP1 with OP3 and OP2 with OP4 - which takes all of five seconds - and then start work on Operator 5. Simplicity itself...
The last page (Figure 5) has the title Miscellaneous, which, I have to admit, is decidedly unhelpful. However, the page itself is anything but, as it deals with all the DX7 parameters that haven't already found a home elsewhere. Note that editing the first parameter to select Monophonic or Polyphonic automatically updates the display of Portamento Mode, which should make the interaction of these two parameters a little clearer to those still in the dark.
You'll probably have noticed that the Voice Name in the example shown is a little on the weird side. This is quite deliberate: I wanted to emphasise the point that with DX7ED, you're no longer restricted to the characters you can input on the stand-alone synth. This software allows you to include lower case letters and special symbols, and all these will subsequently be displayed on the DX7. Well, everything I've tried so far has, anyway.
You want ergonomic efficiency? You got it. Entering the characters that make up the Voice Name is the only DX7ED activity that necessitates you moving both hands. All the other editing functions can be performed using only one hand, leaving the other free to try the sound out on the DX keyboard as you go along. And since you don't even have to enter numeric values when editing parameters, there's no need to take your eyes off the screen. In other words, creating sounds with DX7ED is as quick and painless a task as you'll find in the area of music software.
The listings shown here are parts of some of the DX7ED program's routines, the intention being to illustrate how the program works. The routines are written in BBC BASIC, but production versions of the program will be written in Pascal and distributed in an 'executable only' form.
The basic (no pun intended) idea used in the program is that of displaying sets of related parameter values in labelled boxes on the screen for the user's information. If the user selects a particular parameter for editing, its box 'background' is changed so that selection is graphically confirmed: then when the user enters commands to change the value, the content of the box is updated to reflect that change.
Now, if a parameter represents nothing more than a simple numeric value within a range of allowable values - examples are Operator Level and Keyboard Scaling Depth - the program displays a graphic bar above the parameter value box so that the user has immediate feedback on how much of the allowable range is currently being used.
However, if the parameter value represents a piece of non-numeric data, the program has to display some representation of that data in addition to the numeric value, otherwise the user will rapidly become lost in a sea of unintelligible numbers...
Examples of the display of non-numeric data range from the simple On or Off of the Portamento Glissando (from the Miscellaneous Page) through the slightly more complex KLS Break Point (from the Keyboard Scaling Page) to such climactic delights as the Keyboard Scaling 'keys and curves' diagram (also from the Keyboard Scaling Page) mentioned above and the six Envelope curves discussed last month.
The heart of DX7ED is the main input routine shown in Listing 1 comprising lines 1000 to 1560. This routine organises the display of the parameter value in a box, with a relevant label and graphic bar if required, at a particular place on the screen. In fact, this stage of the process is common to all parameters (except Voice Name, which has its own input routine) and is accomplished by a procedure known as PROCdisplay. I won't go into this procedure any further since much of it comprises a lot of BBC graphic commands that don't, I'm afraid, make very interesting reading. If the user selects a parameter for editing, PROCinput has to change the parameter value and cause both the parameter box value and any associated diagram to be updated.
The procedure definition of input is: DEF PROCinput(title$, par-num%, max%, x%, y%, bar%, do-input%). Looks great, doesn't it? Don't worry - all will be explained. The parameter label is passed into PROCinput via title$; par-num% is the index into a byte array (called par) which holds the parameter values read in from - or to be transmitted to - the DX7 over MIDI; max% is the maximum value the parameter can be and is used by PROCdisplay to work out how much bar to display on the bar graph; x% , y% hold the position on the screen for the parameter box to be drawn at; bar% is a Boolean value which says whether a bar graph should be drawn (this is usually set TRUE for numeric data and FALSE for parameters that need fancy diagrams); and lastly, do-input% is another Boolean value that specifies whether or not data is being input on this call of PROCinput. When the user selects a Page, all the parameter boxes and their diagrams are drawn onto the screen for his information, and only then is he asked for input affecting the first parameter - and since PROCinput has to 'know' how to draw everything, we let it do the work in both cases.
When PROCinput is called, the first thing it does is pick up a copy of the parameter's current value (line 1020, second statement). The procedure then goes into a REPEAT loop (lines 1040 to 1520) which only exits (line 1540) when the user inputs one of the following characters: 'm', '/', 'M', or '?'. I'll describe the meaning of these characters later on.
PROCdisplay is called (line 1060) to put the current state of the parameter onto the screen at the position given in x% and y%. Note that bar% is passed straight through to PROCdisplay - the TRUE just before bar% in the PROCdisplay tells said procedure to draw the parameter box as selected, since we are inputting data.
Moving on, lines 1070 to 1370 are responsible for organising the drawing of non-numeric data representations. Take lines 1140 and 1150 as examples. The IF statement in both lines tests first to see if data is being input for a parameter whose data needs to be represented by 'off or 'on'. The three parameter types tested for are Oscillator Sync, LFO Sync and Portamento Glissando. If the parameter type proves to be one of the three tested for and the parameter value% is currently zero, the AND condition of line 1140 is satisfied and 'off' is drawn above the parameter box on the screen. In much the same way, line 1150 draws an 'on' if the value is a 1.
Once all that drawing has been completed, the procedure enters the inner REPEAT loop (lines 1390 to 1410), which gets an input character from the user. In fact, line 1400 cheats (!) if no data has not yet been input by simulating the user inputting a '/' character, which means 'move on to the next parameter'. If data is being input, then one of the above-mentioned characters is input. We can now see exactly what these input commands do by looking at lines 1430 to 1480.
The characters are used as follows. The comma and full stop (along with their respective Shift functions) are all connected with changing parameter values. Thus, a comma means subtract 1, a stop means add 1, a '<' means subtract 10 and a '>' means add 10. All pretty logical, really. Change of parameter is governed by 'm', which means move backward, and '/', which means move forward. Finally, screen-to-screen movement comes under the domain of 'M', which means move to previous screen, and '?', which means exit present screen or sub-screen.
If the parameter value is to be changed, lines 1430 to 1480 check that the change is legal and then make the change if it is. The parameter is actually updated at line 1500. Naturally, if the requested change is not legal, the command is ignored by the program.
Conversely, if the input is a 'move to' command as opposed to a parameter change, PROCinput exits after redrawing the current state of the parameter in line 1540, with FALSE set for the 'select' in the PROCdisplay call. The routine that called PROCinput in the first place must then look at the character in the key$ to decide which parameter or page to route to next.
Incidentally, the ADVAL(-1) in line 1050 that I managed to ignore in passing checks to see whether there's a typed-ahead character in the micro's keyboard buffer. If there is, the special drawing routines are skipped, since (a) the new input probably makes what would have been drawn out of date, and (b) some of the routines take around a second to redraw and would therefore slow the editing process a little.
PROCinput-LFO is the routine (Listing 2, comprising lines 2000 to 2110) that displays the LFO page that appeared in last month's BeeBMIDI instalment. The general method used applies to all of the pages, however: only the details such as parameter label, number and on-screen position change.
When the routine is entered, the screen is cleared and the page heading is printed (line 2010).
In line 2020, do-input% is set FALSE so that the parameter boxes and display graphics are shown on the screen by the first pass through lines 2040 to 2110 but no data is input. If this weren't the case, no parameter would appear on-screen until some appropriate data was input. And then the program wouldn't be of much use to anyone, would it?
After the first pass, the routine is sent to line 2030, where do-input is set to TRUE. At all subsequent passes through lines 2040 to 2100, the user can alter each parameter to his heart's content and move onto the next when he's finished.
In the case of PROCinput-LFO, as the user exits from a PROCinput call with either 'M' or '?', he also exits from the LFO page and ends up at the Main Menu. This isn't always the case with some of the other routines, however. For instance, if the user exits forward from the intermediate Operator Select page mentioned earlier, he goes on to edit the Operator parameters, whereas exiting back wards returns him to the Main Menu.
The PROCdraw-algorithm routine (Listing 3, comprising lines 3000 to 3220) is included as an example of one of the more complex special drawing routines. DX7ED would be somewhat lacking if the synth's algorithms weren't displayed in full on the screen, since an awful lot of DX editing activities depend on the user selecting an Operator or envelope on the basis of its 'connections' within the current algorithm.
Frankly, I came up against something of a problem here in that I didn't particularly want to write 32 different routines - one for each algorithm. It would have been time-consuming, extremely tedious and, in all likelihood counter-productive: it would have eaten up vast quantities of RAM. What I've done instead is code the algorithms up into a maximum of 12 bytes each, leaving PROCdraw-algorithm to unravel the code and follow any instructions it might find. Lines 3240 to 3340 contain the codes for the first 10 algorithms.
Luckily, seeing as I'm in a particularly generous mood, I'm going to 'decode' the coding system used in DX7ED, so here goes.
The eight bits of the code's first byte are split into three fields as follows: hhwwwnnn. The hh (values 0 to 3) represents the height in Operators minus one (to give values 1 to 4) of the algorithm, while the www represents the width (values 1 to 6). These two values are used in line 3050 to work out where the first Operator should be drawn so that the whole algorithm is centred neatly on the page. The last three bits, nnn (values 0 to 6), represent which of the seven possible shapes of feedback loop should be drawn: this is passed onto PROCdraw-feedback in line 3160, just after the relevant Operator has been drawn.
The rest of the bytes in the code tell PROCdraw-algorithm what to do. At the end of dealing with each byte, the drawing position moves by one Operator to the right (start of line 3180) unless otherwise instructed. Thus a zero byte says simply 'don't draw anything, just move to the right'. When the horizontal row of Operators is reached, the drawing position is moved up a row and hard left (rest of line 3180). It's a bit like the carriage return on a typewriter, except that we move up on the screen rather than down it. As each Operator is drawn, it's connected to those in the row below it, as specified in the code.
As for the code in detail, this is pretty much how it reads. Bit 7 (value 128) means draw a connection to the Operator vertically below; bit 6 (value 64) means draw a connection below left; bit 5 (value 32) means draw a connection below right; bit 4 (value 16) means move up a row and hard over to the left; and bit 3 (value 8) indicates that the Operator currently selected is the feedback Operator. Finally, bits 2, 1 and 0 form the Operator number between 1 and 6.
It's left to lines 3110 to 3160 to check which bits of the code are on and perform the associated drawing operations accordingly.
It's my humble opinion that the DX7ED program provides an extremely user-friendly method of programming what's already become a notoriously unfriendly synthesiser. The idea behind this feature - and the one that came before it - was to describe the package's facilities in some detail and, perhaps more importantly in the long run, give some insight into how the program goes about doing its job.
In fact, the routines described above are coded in a different manner to those in the production version of the program, simply because it's easier to illustrate things this way.
Budding programmers interested in writing their own version of DX7ED (and why not? - only took me the best part of six months, after all) might well be better off making the program entirely table-driven, in the interests of saving space and simplifying the routing control in each of the page modules. The extensive use I've made of named constants (eg. menu%, wave%) in the BBC BASIC program from which the example procedures were taken would be better suited to a compiled language: the enumerated type available in Pascal would be almost ideal.
Technical trivia aside, a production version of DX7ED is now available on cassette (and will be transferable to disk) from EmmSoft at the ludicrously low price of £24.95, inclusive of postage, VAT and all that nonsense: the only proviso is that you be prepared to hang on a maximum of 28 days before delivery. As an added bonus, DX Owners' Club members will be able to claim a discount, full details in a forthcoming newsletter.
And if the demand is there, we'll consider making the program available for other micros, too, so if you've got a specific requirement that's not currently being met, drop me a line care of E&MM and I'll see what I can do.
Feature by Jay Chapman
Previous article in this issue:
Next article in this issue:
mu:zines is the result of thousands of hours of effort, and will require many thousands more going forward to reach our goals of getting all this content online.
If you value this resource, you can support this project - it really helps!