16. SOUND Soundchip If you play a note on an instrument, the volume changes in four steps: Attack - volume raises from 0 to peak Decay - volume falls back to sustain-level Sustain - constant volume during playing of the note Release - volume falls from sustain-level to 0 This can be drawn as a so-called ADSR-envelope with the time on the x-axis and the volume on the y-axis. A typical ADSR-envelope looks like this: * * * * * * * * * * * * * * * |---|-|-----|-|------ A D S R Of course things are never simple in the real world. We will assume that a note has one sharply defined frequency, although 'real' notes usually are a complex mixture of different frequencies, each with its own ADSR- envelope. That's where samples come into the picture, but there they leave our picture again as we will stick to sounds of one frequency. The soundchip in your Atari ST can use eight different 'envelopes' that are rather crude compared to ADSR-envelopes. There is no Decay or Sustain, and it even can be argued that there are only two envelopes: |--| = envelope-period * ** * * slow Attack, fast Release: * * * * * (Attack-bit = 1) * ** * * fast Attack, slow Release: * * * * * (Attack-bit = 0) The envelope-period determines how long it takes to get back to volume 0. Some envelope-variations are possible by changing bit 0-3 in register R13 of the soundchip: bit 0 (Hold) - hold last volume (at end of first period; overrides bit 1 and 3) bit 1 (Alternate) - 2nd period 'mirror-image' of 1st, etc.; Hold + Alternate = fast reverse of last volume and hold bit 2 (Attack) - as described on page 16-1 bit 3 (Continue) - repeat first period indefinitely Here are the different envelope-shapes that can be created by combining the four bit-switches in register R13 of the soundchip: |--|--|--|--|--| envelope-periods * ** * * * * * * * * * &X00.. (bit 0 and 1 are ignored) * ** * * * * * * * * * &X01.. (bit 0 and 1 are ignored) * * * * * ** ** ** ** ** * ** ** ** ** * * * * * * * &X1000 * * * ** * * * * * * * * * * * * * * &X1010 * * * * * * * ** * * ** * * &X1011 * * * * ** ** ** ** * * * * * * * * * * * * * &X1100 * * * * * * * * * &X1101 * * * * * * * * * * * * * * * * &X1110 I count 8 different envelopes, not 10. But I never was good in counting. The envelopes &X0000 and &X0100 can be used for short shot-like sounds (if the envelope-period is short). With the other six envelopes you can produce continuous sound. The soundchip has 16 byte-registers (R0 - R15), with the following functions (range of values is also shown): R0 - period of channel A (= channel 1 for SOUND) : 0-255 (fine) R1 - period of channel A : 0-16 (coarse) R2 - period of channel B (= channel 2) : 0-255 (fine) R3 - period of channel B : 0-16 (coarse) R4 - period of channel C (= channel 3) : 0-255 (fine) R5 - period of channel C : 0-16 (coarse) R6 - noise-period : 0 - 31 R7 - mixer of 8 switches (0 = on, 1 is off!): bit 0 - channel A bit 1 - channel B bit 2 - channel C bit 3 - noise on channel A bit 4 - noise on channel B bit 5 - noise on channel C bit 6 - I/O register R14 (0=input, 1=output; port A) bit 7 - I/O register R15 (port B, i.e. the Centronics port) R8 - volume channel A (bit 4: use envelope) : 0 - 15 R9 - volume channel B (bit 4: use envelope) : 0 - 15 R10- volume channel C (bit 4: use envelope) : 0 - 15 R11- envelope-period : 0 - 255 (fine) R12- envelope-period : 0 - 255 (coarse) R13- envelope-shape (bit 0 - 3) : see page 16-2 R14- I/O (don't touch this register!) R15- I/O (don't touch this register!) Combining R0 and R1 you get a 12-bit value for the period (256*R1+R0, value 1 - 4095) and the same applies to R2/R3 and R4/R5. Converting a period to a frequency and vice versa is easy: period = 125000/frequency and frequency = 125000/period According to my calculator the soundchip has a frequency-range of 31 - 125,000 Hz. Frequencies above 18,000 Hz (period < 7) are not very useful, because most people can't hear such high notes. One sound-period (or perhaps better: one sound-tick) equals 8.10-6 second or 8 ęs. The two equations on the previous page are also valid for the noise-period (R6). The noise-period is used for all channels that are noise-enabled by the mixer (R7). The frequency of the noise ranges from 4032 to 125,000 Hz. The mixer (R7) uses the bits 'the other way around': a set bit means off and a cleared bit means on. Bit 6 and 7 normally are set (=output). In R8/R9/R10 you set bit 4 if you want to use an envelope (determined by R13) and in that case the volume (bit 0 - 3) is ignored completely. Volume 0 will turn the sound on that channel off. Combining R11 and R12 you get a 16-bit value for the envelope-period (256*R12+R11, value 0 - 65535). For the envelope-period you need other equations: period = 7812.5/frequency and frequency = 7812.5/period If my calculator is correct, the envelope-frequency ranges from 0.12 to 7812.5 Hz. One envelope-period (or better: one tick) equals 128 ęs. At the maximum period of 65535 the envelope &X1000 will reach the volume-peak every 8.4 seconds (0.12 Hz). The envelope-period has nothing to do with the sound-period. The former determines the frequency of the volume- changes (see the envelope-shapes on page 16-2). The latter determines the frequency (pitch) of a sound. The chosen envelope-shape (R13) will be used by all three channels. Keep your hands off R14 and R15. The soundchip is used for some I/O-work and you should not interfere with that. That's probably the reason that with some sound-software the drive-light is on although drive A is not used. There are a few Public Domain soundchip-editors around that should make it easy to construct interesting sounds. Although it's nicer to write your own editor. With all the information about the soundchip in this paragraph you should be able to do that. But you'll have to read the paragraph 'Dosound (XBIOS 32)' as well, because there you will find out how to change the registers and, not unimportantly, how to play the sound. SOUND and WAVE A short explanation about the connection between the (two versions of the) SOUND-command and the soundchip-registers from the previous paragraph: SOUND channel,volume,note,octave,time SOUND channel,volume,#period,time Note and octave are converted to period, so the two versions are equivalent. The variables have the following meaning: channel (1,2,3) = channel A,B or C in bit 0-2 of R7 volume (0-15) = volume in R8, R9 or R10 note/octave = (converted to) sound-period period (1-4095) = sound-period in R0/R1, R2/R3 or R4/R5 time ('PAUSE') = used by XBIOS 32: CHR$(130)+CHR$(time) The WAVE-command is more complicated: WAVE mixer,envelope,shape,period,time mixer (switches + 256*noise-period) = R7 + 256*R6 envelope (use envelope: &Xcba) = bit 4 of R8, R9 and R10 shape (envelope-shape) = R13 period (envelope-period) = R11/R12 time = see SOUND The time-parameter in the SOUND- and WAVE-command determines when the next Basic-command will be executed, just like a PAUSE-command does. If you hear a continuous sound (e.g. with envelope &X1000) you have to use another SOUND- or WAVE-command to stop the sound. The easiest way to stop all sound is: WAVE 0,0 ! turn all sound off There are several ways to represent notes and that might confuse you a bit. Assuming you have a rudimentary knowledge of music, the twelve notes in one octave can be represented by letters: C C# D D# E F F# G G# A A# B 1 2 3 4 5 6 7 8 9 10 11 12 (SOUND-notes) For SOUND you use the corresponding numbers 1 - 12. Often the octave- number is inserted behind the note-letter: C1 C1# D1 D1# E1 F1 F1# G1 G1# A1 A1# B1 1 2 3 4 5 6 7 8 9 10 11 12 (SOUND-octave = 1) This is the first octave on my synthesizer. C3 is often referred to as the 'middle C' and that note has a frequency of 262 Hz. If you take C4, you are one octave higher, and this means that the frequency has doubled (524 Hz). The highest note on my synthesizer is C6. With SOUND you can play even higher notes, e.g. C9 (note 1, octave 9; at 16,744 Hz it almost hurts my ears). If SOUND-note and -octave are known, the frequency and SOUND-period of the note can be calculated: frequency%=55*2^(octave+(note-10)/12) period%=125000/frequency% To make things a little more complicated, my synthesizer knows nothing about notes, octaves or periods. It only recognizes Midi-notes, which are bytes with a value of 0 to 127 (bit 7 is not used). E.g. C3 is Midi-note 60. Wouldn't it be nice to know how to convert Midi-notes to SOUND-note and -octave? I think this should work: octave=INT(midi.note|/12)-2 note=MOD(midi.note|,12)+1 Using the other two equations you can now convert Midi-notes to frequency (in Hz) and SOUND-period as well. Here is our octave again, so you can check the results: C1 C1# D1 D1# E1 F1 F1# G1 G1# A1 A1# B1 first octave 1 2 3 4 5 6 7 8 9 10 11 12 SOUND-notes 36 37 38 39 40 41 42 43 44 45 46 47 Midi-notes In chapter 12 you can read a little bit more about Midi. You don't have a synthesizer, but would like to play some simple Midi- music? Or you would like to convert an XBIOS 32 song to a Midi-song for your synthesizer? Then you should know the following Midi-commands (consisting of two or three consecutive bytes): first second third Midi- byte byte byte command &H8n note velocity note off (channel n) &H9n note velocity note off (channel n) &HBn &H7B &H0 all notes off (channel n) &HCn number - program change (channel n) Other Midi-commands should probably be ignored completely if you don't have a synthesizer. The low nibble of the first byte (bit 0-3) determines the channel. E.g. &H80 means channel 0 and &H8F means channel 15. Most Midi-programs present channel 1 - 16 to the user, but internally channel 0 - 15 (&H0 - &HF) is used. The high nibble of the first byte determines the command. A note can have a value of 0 - 127 (bit 7 is always 0), as mentioned before. Of course you'll have to convert a Midi-note to the proper SOUND-note/octave. The velocity also has a value of 0 - 127. For SOUND that has to be converted to a volume-range of 0 - 15 (the SOUND- range is not linear, to make it more complicated). If a note is on, you have to send a 'note off' command later, although you can also use the 'note on' command with velocity 0. A program change can be used to switch to another instrument. You'll need some sort of timer to measure the time between the Midi-commands. That's all. Good luck. Dosound (XBIOS 32) XBIOS 32 (Dosound) can be used to play music in a special format. 'X32' is now generally recognized as the standard-extension for song-files in this format. The operating system takes care of playing the music during Timer C interrupts (every 1/50th second): ' Piece of music of 2140 bytes in INLINE-line INLINE music%,2140 ~XBIOS(32,L:music%) ! play the music You can even play a song continuously with the aid of EVERY. Temporarily stopping a song is also possible, because you can determine where you are: pointer%=XBIOS(32,L:-1) ! song-position (0 if end reached) WAVE 0,0 ! silence You'll have to save the soundchip-registers with XBIOS 28 (Giacces) or you won't be able to continue the song later: DIM register(15) ' Save registers FOR i=0 TO 15 register(i)=XBIOS(28,0,i) NEXT i (...) ' Restore registers FOR i=0 TO 15 ~XBIOS(28,register(i),i OR 128) NEXT i ~XBIOS(32,L:pointer%) ! continue where we left If you use XBIOS 32 to play music, you are advised to switch the key-click off. Otherwise the music will stop as soon as the user presses a key. If you return to the GFA-editor, the key-click is sometimes garbled. Enter some illegal command and GFA will restore the proper key-click and inform you about your stupid error. XBIOS 32 can also be used for sound-effects. I have developed a standard method for building sound-strings from a few DATA-lines. In the following example the sound-string s$ is created: ' commands in DATA-lines : ' REG = 14 parameters for soundchip-registers R0-R13 ' END = end of sound-string ' PAUSE = pause (followed by time in 1/50 seconds) ' VAR = decrease/increase tone: channel,start,+/-step,end ' start and end: 0-255 bounce3.sound: DATA REG,0,0,0,0,0,0,27,248,16,16,16,35,95,0 DATA VAR,3,255,-1,116 DATA PAUSE,255,END RESTORE bounce3.sound ' s$="" DO READ snd$ snd$=UPPER$(snd$) EXIT IF snd$="END" IF snd$="REG" FOR n=0 TO 13 READ snd s$=s$+CHR$(n)+CHR$(snd) NEXT n ENDIF IF snd$="PAUSE" READ snd s$=s$+CHR$(130)+CHR$(snd) ENDIF IF snd$="VAR" READ channel,begin,step,end s$=s$+CHR$(128)+CHR$(begin)+CHR$(129)+CHR$(channel)+CHR$(step) s$=s$+CHR$(end) ENDIF LOOP s$=s$+CHR$(255)+CHR$(0) ! add terminator ' ~XBIOS(32,L:V:s$) ! let's hear the sound In the paragraph 'Soundchip' you already read everything there is to know about the registers. The VAR-command makes it possible to create sounds with decreasing/increasing pitch. You don't have to use the sound-strings as such, you can save a string as a file or you can store the data in an INLINE-line. Samples From GFA-Basic you can surprise the user with a sampled sound if you have a routine that plays the sample. BASCODE.EXE (from Replay) is widespread. You'll have to find suitable samples first. Look out for sound-effects and speech-samples. Personally, I just love the famous Perfect-sample. There are also complete sampled music-pieces around, but such files are always multi-K. Speech Your ST can talk to you with a little help (STSPEECH.TOS), but my current GFA-version (3.07) refuses to cooperate with STSPEECH.TOS. Who can help? Soundmachine In the Soundmachine editor you create a so-called object-file of a song. This file contains both the song and a routine to play the song. The good quality of the music-sound is achieved because the notes are sampled sounds. Soundmachine uses three independent channels in a song. You can also incorporate sound-effects in a song. If you're looking for the highest sound-quality you run a song in X100-mode from a GFA-Basic program. In this mode the processor in your ST is totally dedicated to playing the song, so your GFA-program comes to a complete standstill. For a good compromise between sound-quality and speed you run a song in X66- mode. Now your program keeps running, although much slower, and the sound- quality still is good. You can also use the Mini Soundmachine editor to make beautiful music together. Because Mini Soundmachine makes optimal use of the soundchip, your GFA-program runs almost as fast as normal but the sound-quality is much less than with Soundmachine. You can improve the sound-quality by using a sample on one channel, but that will slow your program down. Try it and decide yourself which song-type fits your program best. I saved the best news for now: Soundmachine is available as Shareware. As this is the only music-program that I can recommend for GFA-Basic, my advice is: find it, use it and pay your share. If you already have Soundmachine, please follow these guidelines: Always enclose the original Soundmachine song (*.SNG) or Mini Soundmachine song (*.MSG) if you spread your GFA-program with music. Other owners of Soundmachine will appreciate it! An Object-file (*.OBJ) is suitable for your GFA-program only. Give information about the song in your program, especially about the use of Flags. Use the extension MSM for an object-file of a Mini Soundmachine song that can be used with any program. The object-file should contain one song in an endless loop. Use the extension X10 for an Object-file of a (compressed) Soundmachine song that plays in X100-mode only. Use the extension XSM for an Object-file of a (compressed) Soundmachine song that can be played either in X66- or X100-mode. Such a song should contain: X66 L-P-[all 3 channels] :0 F0,0 :1 XX R1,0,0 R2,0,100 R3,0,66 J0 :2 X100 :3 [actual song] J3 In your GFA-program you should set Flag 0 to 100 for X100-mode, or to 66 for X66-mode. Use Flag 0 for this purpose only. GIST GIST (GI Sound Tool by Lee Actor, (c) Synthetic Software) is a program that allows you to create 'true' ADSR-envelopes. In GFA-Basic you can use a GIST-sound quite easily. Sounds can be used as sound-effects, but you can also play notes. Sound-effects can be pretty impressive compared to XBIOS 32 sounds. GIST has no music-editor (I hope you write one for me), so you have to do some extra work. If you have a piece of music in Midi- note notation it's easy, because the GIST-driver uses Midi-notes (24-108, see paragraph 'SOUND and WAVE'). TCB Tracker With the TCB Tracker editor (by Anders Nilsson, not Public Domain) you can create music on four tracks (= channels). As in Soundmachine the notes are sampled sounds, so the quality is pretty good. You can play TCB Tracker songs (*.MOD) in GFA-Basic, but only if you use a colour monitor with a vertical frequency of 50 Hz (see page 1-2). At 60 Hz the music may still sound acceptable, but at 72 Hz (High resolution) it's played too fast. Your GFA-program is halted completely and you can only stop a song by pressing . Unless the replay routine is improved drastically, I can't really recommend TCB Tracker for GFA-Basic programs. Staccato I was not impressed by the program Staccato (by Leo de Wit), but I really liked the music (*.MUS) that can be played with that program. A lot of effort was put into the large collection of music-files. What a waste. Unless somebody has a replay routine for Staccato. Or, better still, a program to convert the *.MUS-files (ASCII-format) to XBIOS 32 format. Music Studio Only one question about Music Studio: does anybody have a replay routine for playing Music Studio song-files (*.SNG) in a GFA-Basic program? Please? Procedures (CHAPTER.16) Bell BELL The wellknown bell-sound: @bell(5) ! ring the bell 5 times No Nobell prize for this Procedure. Cont_song_play and Cont_song (page 16-7) \CONTSONG\CONTPLAY Play a song in XBIOS 32 format (*.X32) continuously with EVERY: INLINE music%,1458 @cont_song_play(music%) The key-click is switched off by this Procedure. The music will play continuously, until you either call the Procedure Cont_song_break or Cont_song_stop. Cont_song_stop (page 16-7) \CONTSONG\CONTSTOP Stop the song that was started with Procedure Cont_song_play: INLINE music%,1458 @cont_song_play(music%) (...) @cont_song_stop The key-click is switched on again. Cont_song_break and Cont_song_continue (page 16-7) \CONTSONG\CONT_BRK Interrupt a continuously playing song: INLINE music%,1458 @cont_song_play(music%) (...) @cont_song_break ! key-click switched on (...) @cont_song_continue ! continue where we left the song (...) @cont_song_stop Dosound_init and Dosound_string (page 16-7) DOSND_IN Create sound-strings for Procedure Dosound: @dosound_init The sounds are created as global string-variables. Dosound (page 16-7) DOSOUND Play an XBIOS 32 song or a sound-string from Procedure Dosound_init INLINE music%,1458 @dosound(music%) (...) WAVE 0,0 ! silence @dosound(V:soundeffect$) Gist_init/exit/on/off/stop/prior/stop_all (page 16-10) \GIST\* Play GIST-sound (sound-effect or piece of music): INLINE gist.driver%,3000 INLINE gist.effect%,112 INLINE gist.note%,112 @gist_init (...) ' sound-effect on channel 1, default volume/note, priority 10 @gist_on(gist.effect%,1,-1,-1,10) ' you don't need Gist_off for a sound-effect (...) ' note on channel 2, volume 10, Midi-note 48, priority 1 @gist_on(gist.note%,2,10,48,1) PAUSE 3*50 @gist_off(2) ! note off after 3 seconds (...) @gist_exit ! absolutely essential Msm_init/start/stop/effect/flag/exit (page 16-9) \MINI_SM\* Load Mini Soundmachine object-file and play the music: @msm_init("A:\SONG.MSM",ok!) ! load the music IF ok! @msm_start ! play the music ELSE ' something went wrong ENDIF (...) @msm_stop ! stop the music (...) @msm_exit ! absolutely essential Sample (page 16-8) SAMPLE Play a suitable sample: INLINE sample.bascode%,2794 INLINE sample.adr%,20000 @sample(sample.adr%,20000,5) ! speed=5 PAUSE 10 Sm_init/flag/start_x100/wait/start_x66/stop_x66/space/exit (page 16-9) Load Soundmachine object-file and play the music: \SND_MACH\* @sm_init("A:\SONG.XSM",70000,ok!) ! load the music (70000=buffer) IF ok! @sm_flag(0,66) ! X66-mode @sm_start_x66 ! play the music ELSE ' something went wrong ENDIF (...) @sm_stop_x66 ! stop the music (...) @sm_exit ! absolutely essential Song_play and Song_stop (page 16-7) \SONG\ SONGPLAY & SONGSTOP Play XBIOS 32 song (*.X32) once: INLINE music%,2057 @song_play(music%) ! song keeps playing until finished (...) @song_stop ! stop song prematurely Song_restart (page 16-7) \SONG\SONGREST Restart song that was stopped with @song_stop: @song_stop (...) @song_restart Song_break and Song_continue (page 16-7) \SONG\SONG_BRK Interrupt a song that was started with @song_play: INLINE music%,2057 @song_play(music%) (...) @song_break ! key-click switched on (...) @song_continue ! continue where we left the song The music now keeps playing until the end, or until Procedure Song_stop is called. The following Procedures use SOUND and/or WAVE to produce a sound: \SOUND\ Sound_alarm ALARM Sound_boing_1 BOING_1 Sound_boing_2 BOING_2 Sound_cling CLING Sound_heart HEART Sound_pompom POMPOM Sound_poof POOF Sound_siren_1 SIREN_1 Sound_tideli TIDELI Sound_ting TING Sound_tong TONG Tcb_tracker (page 16-10) TCBTRACK Play a TCB Tracker song (*.MOD): @tcb_tracker("A:\SONG.MOD",TRUE) The replay-routine TRACKER.ROT (for ST's, not STE's) must be in the default-path. You have to press to stop the music. Functions (CHAPTER.16) Frequency (page 16-6) FREQ Returns frequency (Hz) of note/octave: PRINT @frequency(1,3) ! C3 Frequency_midi (page 16-6) FREQMIDI Returns the frequency (Hz) of a Midi-note: PRINT @frequency_midi(60) ! that's C3 also Midi_byte (page 16-6) MIDIBYTE Returns the Midi-note that corresponds with note/octave: PRINT @midi_byte(1,3) Octave (page 16-6) OCTAVE Returns the SOUND-octave of a Midi-note: PRINT @octave(60) Note (page 16-6) NOTE Returns the SOUND-note of a Midi-note: PRINT @note(60) Period (page 16-6) PERIOD Returns the SOUND-period of note/octave: PRINT @period(1,3) Period_midi (page 16-6) PERDMIDI Returns the SOUND-period of a Midi-note: PRINT @period_midi(60)