Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
The AY-3-8910 and its variations were widely used in classical machines like for example the Sinclair ZX Spectrum, Amstrad CPC and Atari ST. It can produce up to three different squarewave sounds simoultaneously, and it also has one noise-generator and one envelope generator.

Allthough it has its limitations, there are tricks to get around a few of them:
1. Fast arpeggios to emulate chords on one chanel.
2. Software envelopes to get around the limitations of the single envelope generator.
3. Matching the hardware envelope to a played tone's frequency for a more sawtooth-like sound.
4. Software tone sweep
5. Using the volume controlls and certain settins to emulate a DAC for digital audio.

The fifth one is more of a hack, so the synth implements point 1-4. There is one software envelope and one tone-sweep parameter for every channel, and overall one noise-sweep parameter and one arpeggiator.

I'm still in the proccess of testing everything, but it should in theory work fine. I just hope that the 4MHz Z80 in my Tiki-100 computer is fast enough to handle 125 updates of the synth per second. Here is the documentation:

Code:
; #######################################################
; #                     #
; #  AY-3-8910 Synthesizer for Z80         #
; #                     #
; #######################################################
;
; Version 1.00
; by Frode van der Meeren
; November 2014
;
; Overview:
;
; This synthesizer is designed to take full use of the
; AY-3-8910's native features. It presents each of the
; three channels as their own instrument, and it also
; provides additional features like software-envelopes,
; frequency sweeps and an arpeggiator.
;
; There is two full chromatic scales implemented. A
; regular equal-tempered scale and the scale of its
; perfect fifths. Additional tones for harmonic chord
; progression is also present, but care must be taken
; when using these with the tones from the scales.
;
; The synth can be implemented in a lot of applications.
; It can be used as a music player, for realtime sequencing,
; with external music and MIDI equipment, music in games,
; or with anything at all that should need to use the AY
; soundchip.
;
; Instructions:
;
; To run the synth, first make sure to include the right
; interface for the AY chip under AYdrv below. The interface
; is generalized, and your driver must ensure that the
; data reaches correctly to the chip in your particular.
; system. See the documentation below for a description.
;
; When the AY interface is in place, make sure to set up
; code that calls synthcycle at a fixed interval. These
; intervals must be very well and evenly timed for best
; performance. The synthcycle routine will keep the
; software envelopes, frequency sweeps and the arpeggiator
; going.
;
; After that is done, call shutup and the synth is ready
; to use. Instruments are by default set to use the hardware
; envelope, so you might want to start by setting up the
; instruments and envelopes. Finally it's time to send music
; messages to play music.
;
; It's always a good idea to call shutup to reset everything
; when the performance is done.
;
;
; #######################################################
; #                     #
; #  Control                  #
; #                     #
; #######################################################
; #                     #
; #  synthcycle:               #
; #   n/a                  #
; #                     #
; #  shutup:                  #
; #   n/a                  #
; #                     #
; #######################################################

synthcycle:
   ld   a,$00
   call   updateinst   ; Update instrument A
   ld   a,$01
   call   updateinst   ; Update instrument B
   ld   a,$02
   call   updateinst   ; Update instrument C
   call   updatenoise   ; Update noise
   jp   updatearp   ; Update arpeggio

shutup:
   di
   call   endArpeggio   ; Arpeggio
   push   ix
   ld   a,$00      ; Instrument A
   call   resetInstrument
   ld   a,$01      ; Instrument B
   call   resetInstrument
   ld   a,$02      ; Instrument C
   call   resetInstrument
   ld   ix,instrN   ; Noise
   ld   (ix+0),$00
   ld   (ix+1),$00
   ld   a,$06
   ld   b,$02
   ld   c,$00
   call   AYdrv
   ld   (ix+2),$00
   ld   (ix+3),$00
   pop   ix
   ei
   ret



;
; The synth has three instruments, where each instrument
; corresponds to one hardware-channel of the AY chip. Each
; instrument has its own proper fully programmable ADSR
; amplitude envelope in software, but it's also possible to
; let an instrument use the hardware envelopes. All the
; instruments also has individual frequency sweep functions.
;
; When using the hardware envelope, you can choose to have it
; steady at a fixed speed, or you can have it match the
; frequency of the tones played. It can also be set to run at
; double frequency in both modes. Any instrument can be set
; to use the hardware synth regardless, but only a single
; instrument can physically perform with it at any time. If
; a new tone is played using the hardware envelope, any
; previous playing tones with hardware envelope it will be
; terminated.
;
; Software envelopes trigger on playTone, and if the previous
; tone was not complete, the volume will not jump down to
; start the attack of the next tone. The attack will rather
; begin from the curent volume when the playTone was received.
; playTone trigger attack>decay>sustain, and endTone will
; trigger release from sustain. Attack and sustain volume
; can be set to any of the 16 possible levels.
;
; Envelopes can be updated realtime, but updates will only
; take effect on the first tone after the update is performed.
; The parameters of setEnvelopes varies depending on the
; envelope type selected for the instrument as well. When
; an instrument is redefined with setInstrument, any tone
; payed by it will be automatically terminated immediately.
;
; Each instrument also has it's own individual frequency
; sweep. skip to the tone table towards the end of this file
; for an overview of the tone-byte format.
;
;
; #######################################################
; #                     #
; #  Instrumental               #
; #                     #
; #######################################################
; #                     #
; #  setInstrument:               #
; #   a = inst (A=0, B=1, C=2)         #
; #   b = tone (Yes=0)            #
; #   c = noise (No=0)            #
; #   d = envelope type (SwE=0)         #
; #                     #
; #  setEnvelope:               #
; #   a = inst (A=0, B=1, C=2)         #
; #   b = volume (4-7 att, 0-3 sus)/HwE follow (No=0)   #
; #   c = attack duration in ticks/HwE double (No=0)   #
; #   d = decay duration in ticks/HwE freq high   #
; #   e = release duration in ticks/HwE freq low   #
; #   l = HwE mode (b0 hold, b1 alternate, b2 attack)   #
; #                     #
; #  playTone:                  #
; #   a = inst (A=0, B=1, C=2)         #
; #   b = tone               #
; #                     #
; #  endTone:                  #
; #   a = inst (A=0, B=1, C=2)         #
; #                     #
; #  sweepTone:                  #
; #   a = inst (A=0, B=1, C=2)         #
; #   b = tone               #
; #   c = sweep duration in ticks         #
; #                     #
; #######################################################

   include   synth\instruments.asm



;
; The hardware noise of the AY can be set and tuned totally
; independent from the rest of the synth, but it is the
; settings of the instruments that define how noise will
; be used.
;
;
; #######################################################
; #                     #
; #  Noise Generator               #
; #                     #
; #######################################################
; #                     #
; #  setNoise:                  #
; #   a = tune (0 = bright, 31 = dark)      #
; #                     #
; #  sweepNoise:               #
; #   a = tune (0 = bright, 31 = dark)      #
; #   b = sweep duration in ticks         #
; #                     #
; #######################################################

   include   synth\noise.asm



;
; One arpeggio can be played at any time. The arpeggio
; will take completely over one or two channels of the
; AY chip. The only three events capable of interrupting
; an arpeggio is when one of the performing instruments
; are re-defined, a new arpeggio is started or when the
; entire synth is reset. In any other case, the only ways
; to stop an arpeggio is to let it run for the remaining
; of it's set duration or by stopping it manually.
;
;
; #######################################################
; #                     #
; #  Arpeggiator               #
; #                     #
; #######################################################
; #                     #
; #  playArpeggio:               #
; #   a(0-3) = inst (0=A, 1=B, 2=C, 4=AB, 5=BC, 6=CA)   #
; #   a(4-7) = volume               #
; #   b/h/l = tones in arpeggio         #
; #   c =  ticks per tone            #
; #   de = ticks of overall duration         #
; #                     #
; #  endArpeggio:               #
; #   n/a                  #
; #                     #
; #######################################################

   include   synth\arpeggio.asm



;
; The tone ranges from C1 to B8. It should be noted that
; the brighter resolution is rather weak, so you might
; not want to use the top octave (C8-B8).
;
; The 5ths scale is a perfect 5th up from the chromatic
; Equal-tempered scale. This is not the same as an equal-
; tempered fifth. These are used mainly for power-chords.
;
; The remaining tones are for harmonic chord progression.
; Major chords are progressed using the Pytagorean scale,
; and minor chords are based on the just-intonated thirds
; from these major chords. All minor chords using these
; tones are therefore very flat compared to the equal-
; tempered and perfect fifth scales! The major chords may
; be slightly detuned from the equal tempered scales, but
; not by much.
;
;
; #######################################################
; #                     #
; #  Tone-table lookup               #
; #                     #
; #######################################################
; #                     #
; #  Tone Byte-Format               #
; #   oooTTTTT: o = octave tr. (0-7), T = tone (0-31)   #
; #                     #
; #  Tones                  #
; #    0-11 = Chromatic scale from C1 to B1      #
; #   20-31 = 5ths from G1 to F#1 (transposing at C)   #
; #      12 = Bb1 (Bb)            #
; #      13 = D1 (Bb Dm)            #
; #      14 = F1 (Bb Dm F)            #
; #      15 = A1 (Dm F Am)            #
; #       0 = C1 (F Am C)            #
; #      16 = E1 (Am C Em)            #
; #      20 = G1 (C Em G)            #
; #      17 = B1 (Em G Bm)            #
; #      18 = D1 (G Bm)              #
; #      19 = F#1 (Bm)            #
; #                     #
; #######################################################

   include synth\tuning.asm



; #######################################################
; #                     #
; # AY-3-8912 interface               #
; #                     #
; #######################################################
; #                     #
; #  AYdrv:                  #
; #   a = AY-register               #
; #   b = Operation (1=IN, 2=OUT, 3=AND, 4=OR, 5=XOR)   #
; #   c = Data out               #
; #   ret d = Data in               #
; #                     #
; #   All other registers than D are preserved   #
; #                     #
; #######################################################

AYdrv:
   include   synth\tiki100ay.asm



; #######################################################
; #                     #
; #  Linear function plotter            #
; #                     #
; #######################################################

   include   synth\linear.asm

Next step will be to make a music player or real-time sequencer that uses this in some way or another.
How are you interfacing with it? This seems like it could be interesting to attempt something similar with the TI z80 calculators.
elfprince13 wrote:
How are you interfacing with it? This seems like it could be interesting to attempt something similar with the TI z80 calculators.

The interface of the chip is just a call to AYdrv (see the shutup subroutine above for an example). Register number in A, register operation in B and data in C. The idea is that anybody using the synth will insert their own module there, tailor made for their hardware. The start of the module is just some code that identifies and performs the right operation based on B. The actual hardware interface can be anything.

I'm planning to use this with the Tiki-100, where the chip is at I/O address $16 (register select) and $17 (data). Here is the code in tiki100ay.asm:

Code:
;
; AY-3-8912 interface
;
; B:
; 1 In
; 2 Out
; 3 And
; 4 Or
; 5 XOr
;
; AY Register in A, Data in C
;
; Other registers kept unchanged
;
   push   bc
   dec   b
   jr   z,AYin
   dec   b
   jr   z,AYout
   dec   b
   jr   z,AYand
   dec   b
   jr   z,AYor
   dec   b
   jr   z,AYxor
   pop   bc
   or   a
   ccf
   ret

AYin:
   push   af
   out   ($16),a
   in   a,($17)
   ld   d,a
   pop   af
   pop   bc
   or   a
   ret

AYout:
   push   af
   out   ($16),a
   ld   a,c
   out   ($17),a
   pop   af
   pop   bc
   or   a
   ret

AYand:
   push   af
   out   ($16),a
   in   a,($17)
   and   c
   out   ($17),a
   pop   af
   pop   bc
   or   a
   ret

AYor:
   push   af
   out   ($16),a
   in   a,($17)
   or   c
   out   ($17),a
   pop   af
   pop   bc
   or   a
   ret

AYxor:
   push   af
   out   ($16),a
   in   a,($17)
   xor   c
   out   ($17),a
   pop   af
   pop   bc
   or   a
   ret
Oh cool, so you're actually designing your program in a hardware-agnostic fashion!

Can't wait to see some demos when you get things up and running.
Spendt some time yesterday to test everything in a convenient Amstrad CPC emulator. Ruled out a few bugs, and now it works just as expected. I also added the possibility to hold the envelope for some time on the attack peak since I thought the decay rate was a bit sharp with the exponential volume levels.

I've written a music sequencer/player that uses the synth, and I'm about halfways at plotting in a test-tune I've composed:
https://www.dropbox.com/s/fmg1or1qtf8yp2m/a.ogg?dl=0
(this is output from the Amstrad emulator, and timing is not perfect as I'm using a loop of nops for delay rather than a timer/interrupt)

The tunes are written with commands like "play 0 A4" and "wait 24", and I have coded a simple java-program that translates the text file to the binary sequencer-format.
I completed the simple music player, and now it runs on real hardware:
Wow.
Next up is the theme from the Mad Monster Manson level of Banjo-Kazooie.

Each tune is anywhere from 1k to 10k depending on complexity and lenght. The tune in the video is about 7k. The player and synth together is slightly less than 4k.


This tune is about 7k as well.
Wow, that's really cool stuff!
That was a lot of fun to listen to, and I can only imagine how much effort went into learning to interface with it. Out of curiosity, was that a song that you tracked yourself, or did you port an existing song to the particular format this synthesizer uses? Either way, I'm very impressed.
KermMartian wrote:
That was a lot of fun to listen to, and I can only imagine how much effort went into learning to interface with it. Out of curiosity, was that a song that you tracked yourself, or did you port an existing song to the particular format this synthesizer uses? Either way, I'm very impressed.
Thanks!

I tracked the song myself using a bytecode-translation tool I made in Java. The song is stored as commands in a textfile, like "play 0 C4", "wait 13", "release 2", "playarp 1 C4 E4 G4 2" and so on. This textfile is converted to a *.tkt bytecode data file. The player works directly with physical tracks (0, 1 and 2), which has turned to be a bit of a limitation.

I plan to write an improved version with virtual tracks, and certainly more than 3, together with a list defining the translation between the virtual channels and the physical channels. It will make things simpler, and easier to use as well. Instead of a designated arpeggiator function, you can play the tones you want in separate virtual channels and set up the translation list to swap between the virtual channels on one physical channel.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement