Shop OBEX P1 Docs P2 Docs Learn Events
AY-3-8910 sound chip — Parallax Forums

AY-3-8910 sound chip

pullmollpullmoll Posts: 817
edited 2014-05-26 12:32 in Propeller 1
I thought I had read somewhere that one of the forum members was going to try to create an object that emulates this chip? I can't find that post (or did I dream it)...
Anyway, I have been trying to convert attached C source into PASM, but I'm yet unsure if it will be feasible to emulate the AY this way. The attached code generates chunks of audio data and needs a streaming device (cog) to output the data at a constant (sample) rate. This would mean 2 cogs, one to generate the data and one to actually play it. I would rather have one cog doing all the work, if that is possible. I think it depends on how fast the 3 sound channels and the noise can be calculated in PASM. If the calculation is faster than the sample rate, the samples could be output immediately after calculation and the sample rate could be locked by using a waitcnt.
Perhaps those who know a bit more than I do about sound on the Propeller can elaborate on this issue?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
«134

Comments

  • LeonLeon Posts: 7,620
    edited 2010-05-15 11:55
    I interfaced one of those to my TRS-80 many years ago. Some of the arcade games at the time used them, IIRC.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Leon Heller
    Amateur radio callsign: G1HSM
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-05-15 13:48
    It will be quite a job to replicate the code in pasm, but it would be a very worthy goal. I'm more familiar with the SN76489 but I think they were very similar chips. 3 tones and a noise generator. One cog would definitely be the goal, and it probably would spend a lot of time in wait states. Calculate everything, OR the signals, output the pin status, wait, repeat.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • JonnyMacJonnyMac Posts: 8,910
    edited 2010-05-15 15:09
    There is a SIDcog object that may be helpful. If memory serves me (haven't played with it in a while) it uses just one cog and handles ADSR for three oscillators.

    http://forums.parallax.com/showthread.php?p=863861

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-15 16:14
    Indeed doing it in one cog would be quite easy.
    The SID chip is many times more complex compared to the ay8910, and still it was possible to do a quite good emulation of it in just one cog.
    I even managed to fit the "analog" multimode resonance filter running in just one cog at a sample rate of near CD quality.

    The AY8910 lacks almost everything that made the SID chip so complex for it's time.
    If we take out Multimode filtering, Oscillator synchronization, Ring modulation, Variable pulse width, Saw waves, Triangle waves and combined waveforms from SIDcog we pretty much end up with an ay8910.
    Then of course we have to alter the registers and severely cripple the envelope part. smilewinkgrin.gif

    We would probable end up with an emulation with a sample rate of almost twice that of a CD thanks to the simplicity of the chip.
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-15 16:31
    Btw, here is a SIDcog medley of 12 different C64 tunes.
    gadgetgangster.com/scripts/displayasset.php?id=344
    Everything you hear is generated by one cog at 31Khz and output with PWM trough a RC filter.
  • pullmollpullmoll Posts: 817
    edited 2010-05-15 16:43
    Ahle2 said...
    We would probable end up with an emulation with a sample rate of almost twice that of a CD thanks to the simplicity of the chip.

    Ok, then I may try to continue with what I began. The AY is really simple, that's true. And still it was widely used on computers and in arcade games, up to 5 chips per game it seems. The comments in the C source pretty much describe every important aspect of the chip and I think I can finish it. I just have to rethink the core update function to do everything for one sample only.

    Thanks,
    Juergen

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/15/2010 4:51:18 PM GMT
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-18 20:29
    Here is a complete emulation of the AY-3-891X (YM2149)

    AYcog features:
    - 60 kHz sample rate
    - YM2149 or AY-3-8910 register structure
    - Supports all waveforms ( Noise wave and 50:50 square wave )
    - Can use advanced envelope tricks to produce other waveforms than square or noice (like the real thing)

    Usage:

    - Start AYcog with the public function "start(right,left)"
    This function starts AYcog with audio out on the pins specified and returns a pointer to the first register of the the AY-3-891X.

    - Put values in the 16 AY-3-891X registers and it should start making sound.

    - One small difference from the real deal.
    It's important that you set the 4th bit of the envelope shape register high everytime you change the register.
    This is because there is no other way for the emulation to know if you have retriggered the register.
    As soon as the emulator has read this bit it automatically sets it low again and it is ready for a new retrigger.
    Example. If you want to put the value 9 (Decay) in the envelope shape register, you should set bit 4 high as well, resulting in value 9 + 16 = 25.
    If you don't set this bit the envelope will not work.

    /Ahle2
  • BaggersBaggers Posts: 3,019
    edited 2010-05-18 21:01
    Nice one Ahle2 [noparse]:)[/noparse] looks like you're keeping me busy with furthering the spectrum emulator, once it's running [noparse];)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-18 21:39
    Thanks Baggers [noparse];)[/noparse]

    Try this code for a complete runthrough of all possible AY sounds.
    PUB Main | AYregisters, i, j, value, playRate
    
      AYregisters := AY.start( audioR, audioL ) 
    
      playRate := 5
      repeat
        waitcnt(cnt + 80_000_000/playrate)
        repeat i from 0 to 15
          value := (?j)&255
          if i>9 and i<13
            value &= 31
          byte[noparse][[/noparse]AYregisters + i] := value
    
    


    LOL
  • AntoineDoinelAntoineDoinel Posts: 312
    edited 2010-05-18 21:54
    Ahle2 said...
    - One small difference from the real deal.
    It's important that you set the 4th bit of the envelope shape register high everytime you change the register.
    This is because there is no other way for the emulation to know if you have retriggered the register.
    As soon as the emulator has read this bit it automatically sets it low again and it is ready for a new retrigger.
    Example. If you want to put the value 9 (Decay) in the envelope shape register, you should set bit 4 high as well, resulting in value 9 + 16 = 25.
    If you don't set this bit the envelope will not work.
    Ahle2, maybe·I'm missing something... but what if you reverse the polarity of that bit? (i.e. the app write normal values, the emu set it to 1 to detect next trigger) wouldn't that work?
    ·
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-18 21:59
    Of course it would..... Why didn't I think of that? Now I feel stupid [noparse]:([/noparse]
    I will correct that.
  • AntoineDoinelAntoineDoinel Posts: 312
    edited 2010-05-18 22:14
    btw, great job (again)!

    next the hammond C3? lol.gif
    ·
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-18 22:42
    Hammond C3, I don't think soo... [noparse];)[/noparse]
    Every PSG emulator I do tend to be simpler than the one before.
    The only PSG I can think of that is more simple than the AY-3-891X is the two channel TIA chip used in Atari 2600.
    The SID chip is A LOT more advanced compared to the AY-3-891X.

    I think 31kHz samplerate for SIDcog and 60kHz samplerate for AYcog speaks for itself.

    Post Edited (Ahle2) : 5/18/2010 10:48:54 PM GMT
  • pullmollpullmoll Posts: 817
    edited 2010-05-19 11:24
    Ahle2 said...
    Here is a complete emulation of the AY-3-891X (YM2149)

    Thank you much! That was really quick!
    Ahle2 said...
    - Start AYcog with the public function "start(right,left)"

    Is there probably a way to have it output on a single pin? I tried to detect if left == right and set a flag in that case, so that ctrb and frqb wouldn't be used. Unfortunately I don't hear anything at all yet. I have to fix my sound circuitry first (I use 1 pin #24 on the DracBlade). Edit: That output is still working with TRS80 and the single duty mode, so it has to be my modification that's wrong... I just hear a click when the cog is started and that's it.
    Ahle2 said...
    If you don't set this bit the envelope will not work.

    Later you said you're going to fix this, so I should probably just map the first 8 registers 1:1 from the cgenie io.spin?
    Edit: I think this is easy to fix. Just test EnvelopeShape, #16 and do the following things if_z only. Then or EnvelopeShape, #16 and write it back to hub RAM!?

    Right now, after adding the AYcog to the list of objects, some games don't want to run anymore. This has to be a bug to do with memory somewhere, because also BASIC is behaving strange and giving me ?OM errors (out of memory). Anyway, that's my problem.


    Thanks again,
    Juergen

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/19/2010 2:06:09 PM GMT
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-05-19 13:38
    Hi pullmoll,

    When you get your circuit right, please let me know what it is (even if it is just a resistor and capacitor) and I'll add that to the next board.

    Sound is going to be a fantastic addition. Hmm - is there a cog free on the MP/M emulation?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • pullmollpullmoll Posts: 817
    edited 2010-05-19 13:54
    Dr_Acula said...
    When you get your circuit right, please let me know what it is (even if it is just a resistor and capacitor) and I'll add that to the next board.
    There is no circuit, but just a 3,5mm jack for the audio out. I used a stereo jack, because I had no mono type available, and just connected port #24 to the output.
    Assuming a 500Ohm aux input on the amplifier and max. wanted 1Vss level, you should probably go with a 1k1 resistor and perhaps a 1µF electrolytic capacitor in series with the output!? Perhaps like this:
    attachment.php?attachmentid=70474
    Dr_Acula said...
    Sound is going to be a fantastic addition. Hmm - is there a cog free on the MP/M emulation?
    VT100 initialized, 0 cogs free.

    Nope. We're out of cogs.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/19/2010 2:04:07 PM GMT
    274 x 169 - 620B
  • AleAle Posts: 2,363
    edited 2010-05-19 15:08
    Ahle2: Reversing the polarity always does the trick wink.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Visit some of my articles at Propeller Wiki:
    MATH on the propeller propeller.wikispaces.com/MATH
    pPropQL: propeller.wikispaces.com/pPropQL
    pPropQL020: propeller.wikispaces.com/pPropQL020
    OMU for the pPropQL/020 propeller.wikispaces.com/OMU
    pPropellerSim - A propeller simulator for ASM development sourceforge.net/projects/ppropellersim
  • pullmollpullmoll Posts: 817
    edited 2010-05-19 15:18
    I got in working in cgenie now, but the sound isn't right. It looks as if it plays no envelope when it should and vice versa.
    I do an or with #16 for writes to register #13.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-19 17:20
    Thank you much! That was really quick!
    


    It was on my ToDo list anyway. You just gave me a reason to do it before year 2020. [noparse];)[/noparse]

    Is there probably a way to have it output on a single pin? I tried to detect if left == right and set a flag in that case, so that ctrb and frqb wouldn't be used. Unfortunately I don't hear anything at all yet. I have to fix my sound circuitry first (I use 1 pin #24 on the DracBlade). Edit: That output is still working with TRS80 and the single duty mode, so it has to be my modification that's wrong... I just hear a click when the cog is started and that's it.
    


    start(0,24) will do the trick.
    The start function takes care of everything including disablling of ctrb or ctra if either left or right is set to 0.

    Later you said you're going to fix this, so I should probably just map the first 8 registers 1:1 from the cgenie io.spin?
    Edit: I think this is easy to fix. Just test EnvelopeShape, #16 and do the following things if_z only. Then or EnvelopeShape, #16 and write it back to hub RAM!?
    


    I know, I was just stupid for not doing exactly that from the beginning... (dooh)
    Right now, after adding the AYcog to the list of objects, some games don't want to run anymore. This has to be a bug to do with memory somewhere, because also BASIC is behaving strange and giving me ?OM errors (out of memory). Anyway, that's my problem.
    


    Okey, keep on debugging. [noparse]:)[/noparse]

    BTW, I will upload a new version with some changes shorthly.
  • JonnyMacJonnyMac Posts: 8,910
    edited 2010-05-19 17:45
    You might want to use -1 as the "don't use" pin designation; this would allow output on P0.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-19 19:43
    Okey, here is a new version with inverted reset bit functionality.
    pullmoll said...
    I got in working in cgenie now, but the sound isn't right. It looks as if it plays no envelope when it should and vice versa.
    I do an or with #16 for writes to register #13.
    That's very strange... according to the AY-3-891X documentation it should enable envelope when bit 4 of register 10, 11, 12 is set high.
    Otherwise you might want to test to change
    Env1          test     amplitude1, val14bit              wz  
      if_nz       mov      amplitude1, envelopeAmplitude
    


    to
    Env1          test     amplitude1, val14bit              wz  
      if_z       mov      amplitude1, envelopeAmplitude
    


    (Remember, that's 3 changes, one for every channel)

    WARNING
    One thing to remember for emulator coders.
    When writing to register 15 you have to "and" the byte with 15 / $F to not alter the "reset envelope flag".
    Else the sound may be wrong if the emulated piece of code tries to (incorrectly) set bits 4-7 of the register.


    Edit....
    pullmoll,
    I just saw that you ACTUALLY was talking about register 13. That's the low byte of the 16bit envelope period register.
    What are you talking about?

    Post Edited (Ahle2) : 5/19/2010 7:53:59 PM GMT
  • pullmollpullmoll Posts: 817
    edited 2010-05-19 23:07
    Ahle2 said...
    Okey, here is a new version with inverted reset bit functionality.
    That's very strange... according to the AY-3-891X documentation it should enable envelope when bit 4 of register 10, 11, 12 is set high.
    Otherwise you might want to test to change <snip>

    That gives a slightly better set of sound effects, but there is still something seriously wrong.
    Unfortunately I have not yet found the bug that causes PAINT.CMD to not work anymore. I guess you could judge by common sense that an accord of 3 tones, right after the startup of a game, that stays until something happens can't be quite right. I can describe the simple game FUSS.CMD sounds. When you move normally, it plays a little tune of 3 or 4 notes. When a rotating cross appears, there is a sweep from low to high frequencies which dies after abt. a second. Finally, when you eat one of the crosses that makes you immune to the poisoned red dots, there is the sound that you now hear right from the start.

    All in all it looks like some or even most effects are done, but at the wrong times. It's hard to describe that. I could try to get my C version Colour Genie emulator up and running, because it has perfect sound.
    Ahle2 said...

    WARNING
    One thing to remember for emulator coders.
    When writing to register 15 you have to "and" the byte with 15 / $F to not alter the "reset envelope flag".
    Else the sound may be wrong if the emulated piece of code tries to (incorrectly) set bits 4-7 of the register.

    I did that and it makes no change.

    Ahle2 said...
    I just saw that you ACTUALLY was talking about register 13. That's the low byte of the 16bit envelope period register.
    What are you talking about?

    According to my specs, register #13 (zero based) is the envelope shape register. The enumeration is in the text file I attached to the first post, the C source of the AY-3-8910 emulation. REG_EFINE (the low byte of the envelope period) is register #11.


    For the records, here's the enum:
        REG_AFINE,
        REG_ACOARSE,
        REG_BFINE,
        REG_BCOARSE,
        REG_CFINE,
        REG_CCOARSE,
        REG_NOISEPER,
        REG_ENABLE,
        REG_AVOL,
        REG_BVOL,
        REG_CVOL,
        REG_EFINE,
        REG_ECOARSE,
        REG_ESHAPE,
        REG_PORTA,
        REG_PORTB,
    
    



    I posted an updated version cgenie-0.1.5 in this thread.

    Edit: Updated again, because I found the reason for the strange sounds: the value REGISTER_OFFSET has to be 1, just like for the YM chip. Where did you get your port numbers from? They're wrong for the amplitudes and everything else following.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/20/2010 6:11:59 AM GMT
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-20 07:26
    According to my specs, register #13 (zero based) is the envelope shape register. The enumeration is in the text file I attached to the first post, the C source of the AY-3-8910 emulation. REG_EFINE (the low byte of the envelope period) is register #11.
    

    According to the official specs the AY has a 2 byte gap between the "enable register" and "channel A amplitude register".
    http://map.grauw.nl/resources/sound/generalinstrument_ay-3-8910.pdf
    The YM-2149F on the other hand has the specs you are talking about.
    http://www.ym2149.com/ym2149.pdf
    Take an unaltered version of AYcog_V0-16.spin·and just enable the YM instead and see if that's works.
    If so, it seems like the Color Genie actually has an YM chip and not an AY.

    /Ahle2
  • AntoineDoinelAntoineDoinel Posts: 312
    edited 2010-05-20 09:54
    Gents,

    by looking at the AY-3-8910 datasheet I got the feeling that R0..R7 and R10..R17 in register name notation is OCTAL and not decimal.
    So registers are really still R0..R15. The width of register select pins (page 5-19) is 4 bits, so it make sense.
    In the end the register map should be identical for both chips.

    I also tried to match this hypotesis with some other source (http://www.atarimagazines.com/v4n7/stsound.html), and that seems to confirm it.
    But consider I never programmed such a chip so I could be wrong.

    Regards
    Alessandro
  • pullmollpullmoll Posts: 817
    edited 2010-05-20 17:05
    I haven't looked into the official data sheet, but Alessandro is certainly right. There is no such thing as a gap in register numbers on the AY, that's for sure.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-20 17:29
    pullmoll said...
    I haven't looked into the official data sheet, but Alessandro is certainly right. There is no such thing as a gap in register numbers on the AY, that's for sure.
    After doing some research it seems like you are right.
    I did all of my coding based on the official AY-3-8910 documentation and I didn't realize they used octal numbers for registers in the AY-3-8910 doc but decimal numbers in the YM-2149F doc.

    pullmoll, it's STILL important that you set all constants to the YM setup and not just "REGISTER_OFFSET=1" like you did
    It should look like
    REGISTER_OFFSET  = 1
    LONG_CORRECTION  = 2
    DUMMY_VARIABLE   = 0
    


    Otherwise envelopePeriod register will be faulty.
  • pullmollpullmoll Posts: 817
    edited 2010-05-20 18:26
    Ahle2 said...
    pullmoll, it's STILL important that you set all constants to the YM setup and not just "REGISTER_OFFSET=1" like you did

    What about attached version 0-17? I removed the constants altogether and made the AYregisters a parameter, so that the calling object defines the register set. That way it is easy for a caller to give useful names to the registers and/or to deal on its own with the digital port A and B.
    Also note that an envelope period of 0 is actually half the length of a period of 1, i.e. it is not zero! This info is from the MAME project's AY/YM emulation.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/20/2010 6:51:40 PM GMT
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-20 21:56
    I will look at your suggestions tomorrow when I'm not tired.... "Coder needs sleep badly"

    Here is an example of playback of AY register dumps from various AY tunes.
    Unpack the ym files to a freshly formated SD card and run "AYDumpPlayExample.spin" and enjoy.
  • pullmollpullmoll Posts: 817
    edited 2010-05-21 00:16
    Ahle2 said...
    I will look at your suggestions tomorrow when I'm not tired.... "Coder needs sleep badly"

    Here is an example of playback of AY register dumps from various AY tunes.
    Unpack the ym files to a freshly formated SD card and run "AYDumpPlayExample.spin" and enjoy.

    Cool! Not as nice as SID songs, of course, but still nice.

    Here's a suggestion for an openNextFile that selects just *.ym files - the others sound a bit strange smile.gif
    PUB openNextFile | i, j, t
        sd.opendir
        repeat i from 0 to fileNumber
          sd.nextfile( @filename )
          repeat j from 0 to strsize(filename)
            if filename[noparse][[/noparse]j] == "."
              quit
          j++
          if filename[noparse][[/noparse]j] <> "Y" or filename[noparse][[/noparse]j+1] <> "M"
            i--
        if sd.popen( @filename, "r" ) == -1
        sd.pread(@buffer, 14)
        repeat i from 1 to 3
          sd.pread(@buffer, 16)
    
    



    The player works with my modified -0-17 as well. It seems the Microtan could have an add-on with 2 AYs, so I'm going to add your code there too. With the caller defining the AYregisters that's no problem.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pullmoll's Propeller Projects

    Post Edited (pullmoll) : 5/21/2010 12:25:19 AM GMT
  • Ahle2Ahle2 Posts: 1,178
    edited 2010-05-22 15:52
    Here is a new version of AYcog.

    AYcog v0.20 improvements:
    - 13% smaller
    - 2.08 times higher sample rate. (125kHz)
    - Fixed some small timing errors
    - Logarithmic volume for "fixed" amplitude values as well.
    (v0.16 had logarithmic volume when using envelopes only)

    FAQ
    Q. Why would it matter to have a better sample rate than twice (according to nyquists theorem) the human range when people can't hear those high frequencies anyway ?
    A. To minimize audiable aliasing distortion when playing high notes.

    Q. How come AYcog has a sample rate 4 times that of SIDcog when both PSGs has got 3 audio channels ?
    A. The SID chip is many times more advanced compared to the AY-3-8910, plus it has got a multimode analog filter.

    @pullmoll
    It's very important that the AY registers are aligned to long address plus a two byte offset otherwise the getRegister subroutine will fail to get the correct values.

    Valid addresses are:
    0 + 2 = 2
    4 + 2 = 6
    8 + 2 = 10
    12 + 2 = 14
    16 + 2 = 18
    etc
    etc
    That's the reason why I don't think it's a good idea to to let the user choose the address.

    Btw, I've added your modified version of openNextFile to the new dump player example.

    I will look at the division by zero problem you were talking about when I find the time.

    /Ahle2
Sign In or Register to comment.