Iseq by Stephen L. Judd, sjudd@ffd2.com last revised: May 2002 Visit http://www.ffd2.com/fridge/ for the latest updates. Introduction ------------ Iseq is a program for composing and playing music on the C64. It is written totally from scratch, with three major design goals: it should be powerful, it should be efficient, and it should be fun! The iseq philosophy starts with the idea that everything is a sequence. SID effect? A sequence of values written to SID registers. A melody? Sequence of notes. A tune? Sequence of melodies (and rhythms, etc. of course). The next part of the philosophy is that instead of providing rigid built-in effects and such, iseq provides _tools_ for (easily) creating effects, notes, tunes, and so on. The tools are easy to use, so things stay simple, but give you, the composer, a lot of flexibility in the process. To round it all off, I tried to come up with methods of designing instruments, arpeggios, tunes, etc. that was easy and efficient to use (single keystrokes, intuitive interface, that sort of thing), and a player that was efficient byte- and cycle-wise. Did I succeed? Well, you will be the judge! SLJ 3/02 Contents -------- I. General information/overview II. Editing notes and tunes III. Editing Instruments IV. Using Iseq tunes in other programs I. General :::::::::: There are a few things to keep in mind, and a few standard keystroke conventions. First, this player is a note-duration based player, as opposed to a tracker. Second, to play notes, the keyboard is arranged like a musical keyboard: w e t y u i p a s d f g h j k l : ; corresponding to the notes # # # # # # # c d e f g a b c d e Octaves are selected using +/-, and pressing the above keys will specify a note in the selected octave. Moreover, pressing shift+key uses octave+1, and C=+key uses octave-1; this way, you can enter notes spanning three octaves, without resetting the "base" octave. Third, the back-arrow key <- is the catch-all "exit" key. Any time you "enter" something, be it a menu, the instrument or arpeggio editor, whatever, you typically "exit" it using the backarrow key. Fourth, online help is available for all screens -- just press CTRL-H for a list of valid commands for the current situation. Finally, if you get into trouble -- put the player into an infinite loop, for example -- pressing rs/restore will reset Iseq and usually get you out of it. If not, you can usually type SYS 32768 after a reset. If THAT fails, then reload just the editor (iseq1.0) and type SYS 32768 -- usually the player isn't disturbed. And if THAT fails, then load up an ML monitor and save all the data from $0ca0 to the end (somewhere around $1900 or $2000). Finally finally, just because it's handy, you can listen to a tune from BASIC using SYS 4102 -- it just runs a simple interrupt routine. II. Making Tunes :::::::::::::::: Iseq allows multiple tunes -- for example, a main game tune and a highscore tune -- using the same player. In iseq, a tune is organized into two parts: "note" sequences and "tune" sequences. A note sequence is, funnily enough, a sequence of notes, durations, and related instructions. Every note sequence is assigned a label, like "A" and "B". You can think of this as a folder, containing notes and all the information for making sounds; if you're a coder, you can think of this as a subroutine, that can be called by the tune player. A _tune_ is a sequence of note folders, like AABA. A tune sequence can also contain certain global commands, like transponse, change tempo, and more. So, notes are organized into note folders, and note folders are organized into tunes. With that in mind, the main screen looks something like this: ----------------------------------------- iseq v1.0 slj 3/02 CTRL-H for help ----------------------------------------- v1: tempo A B A C ... v2: v3: ----------------------------------------- A: inst c c# d d# e f f# ... B: C: D: ... ----------------------------------------- status message ----------------------------------------- The upper section (v1: etc.) contains the actual tune sequences. The lower section (A: B: etc.) contains the note sequences. Note that, at any time, you can press CTRL-H for a screen listing all available keypresses. When editing, in addition to the cursor keys, you can use < and > to move left and right in big steps. The "global" commands from the main screen are (and are all listed in the online help): ctrl-p Play tune C=+ C=- Double/halve the play speed (fast-forward, slow down) shift-clear Clear all notes * Reset SID (turn off the volume!) rs/restore Reset The main functions of the main screen are accessed using the function keys: F1 - Edit tunes (or cursor keys) F3 - Edit notes (or cursor keys) F5 - Edit instruments F7 - Load/save disk menu F8 - Import old data When editing a tune, below, we will start with editing a note sequence, and then move to putting note sequences together to make a tune. ============ Note Folders ============ Cursor down to the note editor (you can also use F3). Note folders can be any length, contain any number of instruments and arpeggios, and so on; the folders are for _organizing_ the music, not limiting it. You could write an entire tune using a single folder, but using multiple folders helps to organize the tune into different parts, reuse parts, etc. A note folder can contain the following instructions for the player: play notes, as you would think! hold current note set duration set instrument set arpeggio turn gate toggling on/off turn note resetting on/off As you can see, there aren't a whole lot of commands and options, mostly because all effects and such are contained within the instrument (which will be discussed later). What the above commands do is let you control the behavior of the player. Editing Commands ---------------- For navigation, the cursor keys are used along with < and > to take large steps left and right. Cutting and pasting is initiated using ctrl-x or ctrl-c. Use the cursor keys to select the block, then press ctrl-x to cut the block or ctrl-c to copy it. Then it's good old ctrl-v to paste it. Entering Notes -------------- To enter notes, the keyboard is arranged like a musical keyboard: w e t y u i p a s d f g h j k l : ; corresponding to the notes # # # # # # # c d e f g a b c d e f You select an octave using +/-, and the above values will be entered in that octave. Moreover, pressing shift+key uses octave+1, and C=+key uses octave-1; this way, you can enter notes spanning three octaves, without resetting the "base" octave. Durations --------- You've got two kinds of players: trackers, and note-dur players. This one is a note-dur player, which means you specify how long to hold a note. The durations are stored in a table, and there are 16 durations available. You can set the 16 duration values to anything you want, and changing any value will change it everywhere it is used in the player. In many note-dur players, you specify a duration for every note. In iseq, you specify a duration, and all subsequent notes will have that duration. For example, a sequence like dur=4 a b c d dur=6 d# e f# would use the dur=4 table entry for notes "a b c d", and use the dur=6 table entry for notes "d# e f#". There is another note, called the "hold" note, which simply holds the current note for the current duration. So, for example, dur=4 a b c h h would hold note "c" for two extra duration values -- the note "c" would last three times longer than the notes "a" and "b". The hold note provides an alternative to continuously setting durations. There are two ways of selecting durations. The quick way is to use the number keys 1-8 for durations 1-8 and shift 1-8 for durations 9-16 (one keystroke). The second way is to press CTRL-D. This will bring up a list of durations, which you can select using the cursor up/down keys. Moreover, pressing cursor-right will allow you to specify the duration _value_. So, to let duration "6" have a value of 192, you'd cursor down to entry 6, press cursor right, and enter 192. Durations can have values from 0-255. Finally, ctrl-shift-D will let you edit the duration table without selecting anything. Setting Instruments ------------------- To set an instrument, press CTRL-I. This will bring up a list of instruments, which you can select using the cursor keys, using RETURN or the back-arrow to exit. As with durations, ctrl-shift-I will let you You can define a total of 16 instruments. Instruments are described in section III, but instruments contain all the information for what sound will be generated when you play a note. There is only one instrument active at a time for each voice. Setting Arpeggios ----------------- Similar to instruments, CTRL-A will bring up a menu of arpeggios, which are defined using the arpeggio editor (accessed from the instrument editor). A total of 15 are available, with arpeggio 0 being no arpeggio. Arpeggios are also described in detail in section III. Gate Toggle ----------- Although this will be described in detail later, this switch determines whether gate toggling will take place in the instrument. With SID, a sound is started by setting the "gate" bit for the voice, which starts the attack/decay/sustain cycle (i.e. it turns the sound on). To start the decay cycle -- to turn the sound off -- the gate bit is cleared. In iseq, the player can send a signal to an instrument, telling it to clear the gate bit at some specific time (for example, if there are only two player calls left for the note). This switch enables/disables this signal. The reason for doing this is that with gate toggling off the notes can be "slurred" together, that is, played smoothly and continuously, whereas with gate toggling on a different kind of sound can be generated (a more staccato sound, for example). Since both can be useful in a single note sequence, this switch is placed here. To enable/disable gate toggling, use b/shift-b (think "b"it; g/shift-g is used as a note!). Note Reset ---------- Finally, the note reset. Whereas gate toggling deals with the "end" of notes -- turn the gate off when the note is almost finished -- note reset deals with the beginning of notes. Many instruments contain a sequence of values to be written to some SID register; similarly, arpeggios contain a sequence of note values to be written to SID. The instrument uses a counter as an index into these sequences; the counter starts at zero and counts upwards, sometimes cycling back through zero at the end of the sequence. With note resetting on, the counter is reset to zero, and the instrument sequencer restarts. With note resetting off, as you might expect, the sequencer doesn't reset, and just continues onwards. Another use for this is related to the gate toggle. In general, an instrument has the gate turned on upon every reset. If the gate has been turned off, and resetting is disabled, then the notes will continue to fade away as they are played. All of this will be explained in more detail in the instrument design section. n/shift-n is used to enable/disable note resetting. Note end -------- Finally, to indicate the end of the note sequence, press the <- backarrow key. Once the note player hits this, it returns to the tune player, for the next sequence. And that concludes the note editor. Once notes have been entered into a folder, they are assembled into a tune using the tune editor. =========== Tune Editor =========== Cursor up to the tune editor (or press F1). The tune player knows how to do the following: - play note sequence - set tempo - ritard - set gate toggle delay - transpose - toggle hard SID restart - wait - sync - stop - goto/loop This is where the different parts of the tune are stitched together. As you can see, the tune player calls note sequences (much like calling a subroutine), and can perform various "global" functions which affect the playing of that sequence. It can transpose notes, it can wait for a 'sync' signal from another voice, it can affect the gate toggle, and it can alter the tempo. Again, there are just a few basic functions, but they give you control over the player. Play note sequence ------------------ Keys a-x select the note sequence to play. Set Tempo --------- The iseq player is perfectly happy to use the CIA timers for the interrupt, and can have a list of different timer values, or tempos. This gives extreme flexibility over the tempos used by the tune, instead of limiting the tempos to some multiple of 50/60Hz. The "set tempo" function should NOT be used if the player is going to be called from a VIC interrupt, but only when using the built-in routine (SYS 4102), or CIA timer #1 in general. Ctrl-T brings up a menu of 8 possible tempos; as always, use cursor up/dn to choose, and use cursor-right to enter a tempo setting. These settings are written directly to CIA timer #1, so use with care! Ritard ------ Ritard gives a way of slowing the piece down, without modifying the IRQ rate using set tempo, above. Press shift-R to enter a ritard value; the higher the value, the slower the piece will become. Essentially, a value of 0 plays at full-speed, a value of 1 at half-speed, a value of 2 at 1/3-speed, etc. Set Gate Delay -------------- As explained earlier, a note can have its gate toggled near the 'end' of its life. More specifically, when a note is played, it's duration becomes the intial value for a counter. At each player call, that counter is decremented, and when it reaches zero the next note is read in. When that counter is equal to the gate delay value, the instrument is told to begin the gate delay. Said another way, when the note has N player calls left in life, start the note decay. Press shift-G to enter a gate delay value (0=no gate delay). Set Hard Restart ---------------- Sometimes SID gets upset when you start changing his registers in certain ways. Turning a "hard" restart on will turn on the test bit (bit 4 of $d404) every time a new instrument is selected. Not on every note -- just every new instrument. By default, this is off. Transpose --------- Transposing moves _all_ notes up or down by some specified amount. You can write all your tunes in the key of C, and use transpose to shift them to another key (giving a different 'feel', in general). You can also use it to transpose individual sections, up or down, by a specified number of half-steps. Press shift-T to specify a transpose value; valid values are -12..12, giving a full octave transposition range. Wait and Sync ------------- Wait and Sync are very simple, and very useful. Wait simply halts further processing on a voice, until a "sync" signal is sent out. "Sync" sends out that signal. As an example, say that a tune starts out with some intro, in voice 1. Voices 2 and 3 can just Wait until voice 1 sends a Sync signal, at the end of its intro. Currently, sync is not "retroactive" -- that is, if v1 is waiting for a sync signal, and v2 sends a sync, v1 will start processing on the _next_ cycle. I will work on this, to figure out a better way! (Tunesmith had a good way, but I don't remember anymore!) Shift-W inserts a Wait, and Shift-S inserts a Sync. Stop ---- Stop simply halts all processing, period. Shift-Z does a Stop. Loop/Goto --------- Finally, the tune player can loop backwards to some specified point (e.g. the beginning of the tune, to reset the tune). The loop lasts forever, i.e. it is a straight goto. Press shift-L to enter a loop, and move the cursor to the point which should be looped to (up to -255 distance from the current position). Multiple tunes -------------- Sometimes, it's nice to have multiple tunes with just a single player, for example a "main game" tune and a "highscore" tune, so that an outside program can play different tunes with a simple Init call. In iseq, a "tune" is just a pointer to some note data; all the player has to do to change tunes is to change pointers. The point here is that it's really easy to do multiple tunes, so it's in there. The first step is creating a new tune, using ctrl-shift-N. This creates a new, empty tune; pressing it again will create a new, empty tune. Up to eight tunes are available. Ctrl-shift-T is used to select which tune to edit. This will bring up the usual menu, where you can use the cursor keys to select and name the different tunes. To play a specific tune, you just lda #tune jsr $1000 as described in section IV, below. And that concludes the Note and Tune editors. Now it's time to actually make some sounds, using the Instrument Editor! III. Instrument Editor :::::::::::::::::::::: The instrument editor screen looks like the following: d415 [] d416 [] d417 [] d418 [0f] atdk [00] surl [f0] freq [] pwid [0000 0100 0200 0300 0400] creg [41] frq+ [] gate [] fixf [] 0000 [] type amp fr ph type amp fr ph + sin 0100 00 00 + sin 0000 00 00 + tri 0000 00 00 + sin 0000 00 00 + con 0000 00 00 + sin 0000 00 00 The idea is that each entry above -- $d418, creg, and so on -- is either a SID register or a memory location to modulate. An instrument controls what is written to each location; specifically, it writes a _sequence_ of values to each location. The sequence might be a single value, it might be a series of values, it might be generated algorithmically -- and it might be nothing at all. The bottom part of the screen ("type amp" etc.) is for the "sequence generator" -- a way of generating sequences of values. For each parameter, you choose the length and type of sequence and either manually enter the values or use the generator to generate them. The values are updated in real time, so if you have the instrument active (or a tune playing) you will hear the changes as you make them. 1. SID basics All of the parameters except one relate to SID in one way or another; therefore, to be truly effective at designing instruments you need to be familiar with SID. SID is not hard to understand at all, and with just a little bit of playing around you'll get the hang of it. If you already have the hang of it, skip to the next section! The most basic things to understand are: frequency, waveforms, ADSR, and gating. Frequency is trivial -- a 16-bit number that describes the frequency of the note. What SID does is add that number to a 24-bit counter on each machine cycle, and when the counter turns over it updates the waveform. The waveforms determine how the sound "sounds", and of course SID has four: triangle, sawtooth, pulse, and noise. The pulse waveform also uses the "pulse width" settings. ADSR stands for Attack Decay Sustain Release, and affects the _volume_ produced. Think of it as a volume knob on your stereo, where you start it at zero, turn it up to full volume, turn it down to some sustain volume, and later turn it back down to zero. The four ADSR numbers determine the _rate_ at which the above operations are performed: Attack -- how fast the volume rises from zero to max Decay -- how fast the volume decays from max to sustain Sustain-- volume to sustain at Release-- how fast the volume decays from sustain to zero And finally, the ADSR cycle is controlled by the "gate" bit: when it is set to 1, the attack cycle begins and goes to the sustain cycle. The note is held at the sustain volume until the gate bit is set to 0, at which point the release cycle begins. That's all gate does: start attack, and start release. The SID registers that define a single voice are therefore $d400-$d401 Frequency $d402-$d403 Pulse width $d404 Control register: bit 0 = gate bit bit 4 = triangle waveform bit 5 = sawtooth bit 6 = pulse bit 7 = noise $d405 Attack and Decay bits 4-7 attack rate bits 0-3 decay rate $d406 Sustain and Release bits 4-7 sustain volume bits 0-3 release rate So, a simple instrument would be $d406 = $f7 sustain=15, release=7 $d404 = $21 waveform=sawtooth, gate=1 $d400 = $1000 frequency = $1000 And to start the release cycle, $d404 = $20 To change the instrument to triangle and start the release cycle, $d404 = $10 and so on. There are of course zillions of SID references around, in books and on the net. CTRL-H will also bring up a description of the different registers, and which bit does what. My advice is: just play around with it for a bit, then once things make sense go look up more advanced things like filters and ring modulation in a book or on the net. 2. Parameters The first nine parameters are SID registers; the first four are absolute, the next five are relative to the current voice, and the last four are special. Most parameters are 8-bits, but the freq and pwidth parameters are 16 bits. The last four parameters are tied much more closely to the player, and are as follows: frq+ Relative frequency modulator gate Value to write when gate is turned off fixf Restore the original frequency after specified time 0000 User location When a note is played, the frequency is stored in a location inside the player. The frq+ sequence values are _added_ to this value, then written to the SID frequency register. The player will send a signal when it is time to turn the gate off (as specified by the "set gate delay" instruction in the tune sequence). When an instrument receives this signal, it writes the "gate" value to the control register (e.g. $d404). Note that the whole byte is written, not just a single bit (SID registers are read-only, and using this parameter makes life simpler for the player). The "fixf" parameter restores the original frequency after a certain time. A combined drum+bass, for example, might want to set the frequency to some high noise value for two clock ticks, then set it to a pulse at the original frequency. This would be done with an instrument like freq [4000 4000] creg [81 81 41 41] fixf [2] i.e.: restore the frequency after two clock ticks. Finally, the "user" parameter can be set to any memory location -- that is, you can choose where specifically to send a sequence of values. One use is for synchronizing music and code, for example. The actual memory location is set from the same screen where the type of sequence is chosen. 2. Sequences Sequences -- or "modulation schemes", if you like -- are written to reigsters, one per player call. Each parameter can have one sequence assigned to it. Sequences can be "continuous", i.e. continuously looping, or "one-shot", in which case the values are written once. Sequences have two components: there are sequence _types_, and sequence _values_. There are five different sequence types: and certain types can have different lengths (sequence length=1, sequence length=16, and so on). The lengths are always a power of two. Pressing the '=' key brings up a screen where the sequence type and length for each parameter (along with the user parameter value) may be set. When this screen is exited, these settings are used to compile instruments into the player -- that is, each sequence type produces some specific code which the player will call if the instrument is activated. Once the sequence settings are in place, the sequence _values_ may be changed from the main instrument screen. The sequence types are: Skip parameter. An absolute sequence of values to be written to the register. Ramps have three values: start value, stop value, step value (much like a FOR-loop). The ramp up starts at the start value, and adds the step value until it hits the stop value. The ramp down is similar, but subtracts the step value -- enter a step value of "1" if you want a ramp down to subtract 1 each time. Adders have a start value and a set of sequence values. An adder starts at the start value, and keeps adding the sequence values to it to get a running total. An adder with a single sequence value is like a ramp with no end value. 3. Sequence Generator The sequence generator is used to, well, generate sequence values. For example, it would be a big drag to type in every number in a long sequence. Press shift-enter at some parameter to use the sequence generator on that parameter. The idea of the generator is kind-of like SID: you have six different "generators", each of which can have its own waveform, amplitude, frequency, and phase, and they are all added together to get a combined waveform, i.e. a sequence of numbers! The waveforms available are: sinusoid -- goes between -1 and 1 ramp up -- linear ramp from 0 to 1 ramp dn -- linear ramp from 1 to 0 triangle -- goes from 0 to 1 back to 0 noise -- random values between 0 and 1 constant -- 1 The amplitude multiplies the basic waveform; for example, a "ramp up" with amplitude 123 would become a linear ramp from 0 to 123. The frequency says how fast the waveform values are stepped through. Each waveform is 256 values, and the values are stepped through with some code like x = x + frequency lda waveform,x The phase is just an offset, in particular the initial value of the x counter above. Finally, each generator may be either added to or subtracted from the total waveform, by using the "@" key to toggle addition and subtraction. As always, ctrl-h will bring up a help screen for the generator. 4. Arpeggios Like the instrument parameters above, an arpeggio is simply a sequence of values to be written to SID. The difference is that when writing a tune, you might want to have three different arpeggios for a single instrument, and they need to be any length, not just a power of two. Hence the arpeggio editor, accessed from the instrument editor using ctrl-a. There are 15 arpeggios available, and arpeggio 0 is the "no arpeggio". Each arpeggio can be any length, and can either be one-shot or continuous, as before. There is just one length restriction: the _total_ length must be less than 256 -- that is, there are only 256 bytes available for arpeggio data. Chances are _awfully_ good you won't get here. Unlike instruments, arpeggios are not compiled, so changing their length is pretty easy (but don't change lengths while a tune is playing; arpeggio data is stored under note data). Arpeggios are built-in to the player. There are two editing modes, toggled using the '=' key. In the first mode, values are displayed; in the second mode, arpeggio names and type/length information is displayed. The only difference is that you can choose names from the second mode, and choose values from the first. To choose values, simply press cursor-right, and enter a list of values at the prompt. The program will then parse the values and enter them into the arpeggio. The values are added to the current note, and the corresponding frequency stored to SID. So, an arpeggio of 0 4 7 first stores "note+0" to SID, then "note+4", then "note+7" -- it doesn't keep a running total like an adder would. "note+1" is always a half-step above "note" -- e.g. if note="c" then note+1="c#". The arpeggio speed is selected using CTRL0-9. And that pretty much covers instrument design! IV. Using iseq tunes in other programs -------------------------------------- An iseq tune looks like the following in memory: $0ca0-$0fff Editor stuff -- not needed by player $1000- Player: $1000 Init $1003 Play $1006 Automatic play (e.g. sys 4102 from BASIC) $1009+ Player code: [identifier strings] [player variables] [player routines] [instrument sequence data] [compiled instruments] [arpeggio data] [tune data] [note data] The first thing to notice is that while a bunch of data is stored before $1000, it is not used by the player and can be erased (it contains things like instrument info and names, needed by the editor but not the player). There are three stubs, starting at $1000. The first is "init", which of course initializes the player. If multiple tunes are contained in the player, .A should first be loaded with the tune number: lda #tune jsr $1000 If there's only one tune, the contents of .A don't matter (the program checks to see that .A contains a valid tune, and if not defaults to tune 0). After that, it's just a matter of calling $1003 in an interrupt -- the usual way. There is also a stub at $1003 -- SYS 4102 -- which adds the player to the normal system interrupt routine, for e.g. playing from basic. Note again that the iseq editor runs off of the CIA interrupts, and can have different timer settings for different tempos. If a tune uses different tempo settings than the frame rate then things will obviously not work quite right if called from a VIC interrupt!