My POKEY note table - Forum Atarum

Jeśli chcesz wziąć udział w dyskusjach na forum - zaloguj się. Jeżeli nie masz loginu - poproś o członkostwo.

  • :
  • :

Vanilla 1.1.4 jest produktem Lussumo. Więcej informacji: Dokumentacja, Forum.

    I have made a POKEY note table in .xls format

    The table has these settings:

    $Ax (square wave) for 64 khz, 15 khz, and 16-bit
    $Cx (saw wave) for 64 khz, 1.79 mhz, 16-bit, includes RMT C and E settings
    $2x (triangle wave) for 64 khz, 1.79 mhz, and 16-bit
    $8x plus 9-bit for 1.79 mhz and 16-bit
    $4x for 1.79 mhz and 16-bit, there are two tables, one of them is a mod 3 table, uses multiples of three like $Cx

    Also has reverse 16-bit settings. You set 16-bit mode, play first channel and make second channel silent.

    $Ax - uses 64khz clock. Standard $Ax table, then 50% duty cycle NES wave starting at A#3 and going down to C2

    $8x - 1.79 mhz clock. Distorted guitars. Two note tables, plus a third table with vibrating sounds.

    $4x - 1.79 mhz clock. Distorted guitars. Three note tables, plus a third table with vibrating sounds.

    It's in English, maybe someone can translate to Polish?

    Still not finished, I will add SKCTL=$8B and hi-pass AUDCTL=$02, $04, $06 settings.
    • 2:
    • CommentTime21 Apr 2020 zmieniony
    Thanks for this!
    When you finish, somebody would translate, not sooner (additional work). If nobody else, then me.
    I think a good idea is to place this on
    Good idea.

    I am also trying to learn Polish ... it's very hard lol. :) Maybe by the time the note table is finished.

    I hope a new tracker will come of this work. Meanwhile, my $4x reverse 16-bit table has been hacked into RMT on the AtariAge forum. Might be useful, maybe, for now.
    • 4:
    • CommentTime21 Apr 2020
    is it working the same for PAL and NTSC machines?
    Not sure. I tested everything in NTSC and tuned by ear against the standard $Ax table.
    Here are RMT hacked with reverse $4x table into 6 distortion. You place notes in first column. Not sure if the hack is working or not. R0ger did the hacks.
    • 7:
    • CommentTime21 Apr 2020


    It's in English, maybe someone can translate to Polish?

    Sure, we can do it.
    It's a long way from being done. $4x reverse 16 took me two months to do. I had to listen to all 65,536 frequencies.
    • 9:
    • CommentTime21 Apr 2020
    Wow! Incredible hard work.
    I also did work on $4x 1.79 mhz plus SKCTL=$8B two tone. Distorted guitars, plus the two $Cx note tables, but they are run through a fuzzy distortion. Very close to finishing that one.
    Added a new update ... SKCTL two tone mode for $Ax distortions ...


    More work remains
    I have started on a new note table setting.

    AUDCTL=$64 (1.79 on 0 and 2 channel, plus hi pass filter on 2 and 0)


    Using $2x distortion, placing different frequencies in AUDF0 and AUDF2 to make distorted guitar sounds. These sound sharp, and I think I can get a greater range than with other settings. Sounds promising!

    Now to step through 65,536 frequencies ...
    • 13:
    • CommentTime9 Jul 2020 zmieniony
    Maybe I do not understand, but I have read in xls:

    "15 khz tables are identical to 64 khz tables but transposed down 2 octaves."

    In my opinion that's not true. the 15khz clock is not taken from 64khz/4.
    "For timers using the 15KHz or 64KHz clock, the period is N+1 ticks, where each tick is 114 cycles with the 15KHz clock and 28 cycles with the 64KHz clock"

    So (4*28=112)!=114 and I remember that it lead to quiet audible frequency drift.
    That may be accurate. 15 khz mode for me seems to work very well in the lower frequencies using the standard 64 khz table, it gets a little out of tune in the higher ranges, especially around C4.
    • 15: CommentAuthorilmenit
    • CommentTime15 Jul 2020
    It's great work. I'm thinking if this could be somehow automated with some sound tuning tool, instead of listening.
    I agree. My ears tend to bleed after awhile. :)

    Working on another 65,536 frequencies for another setting. This time, it's $2x on channel 0, 1.79 mhz on 0 and 2, and hi pass filter. Distorted guitars but with a higher tuning range.
    I will also add, the 16 bit tables on $Cx (both iterations), $2x, $4x (both iterations), and also the 1.79 mhz tables on $Cx and $2x, all were tuned by ear using the $Ax 8-bit and 16-bit settings as an audio reference. It might work better if we had a means of checking these with a tool, maybe.
    • 18:
    • CommentTime31 Jul 2020 zmieniony
    Hi, maybe use some tool to decode frequencies?
    Tried to play a bit with aubio library and wav recorded from apokeysnd.dll, the result table enclosed (out.csv)
    The sounds were only 1 frame long, so the lowest frequency decoded was 50Hz.
    This is for plain vanilla DSOUND like turbo basic stuff.

    Generation (thanks to antrykot, win32 python):
    from ctypes import *
    from array import array
    import wave

    pokey = CDLL(r'...\path_to\apokeysnd.dll')

    def sound(chn, n, gen, amp):
    pokey.APokeySound_PutByte(c_int(chn * 2), c_int(n))
    pokey.APokeySound_PutByte(c_int(chn * 2 + 1), c_int(gen * 16 + amp))
    pokey.APokeySound_PutByte(c_int(8), c_int(0))

    def dsound(chn, n, gen, amp):
    pokey.APokeySound_PutByte(c_int(chn * 2), c_int(n%256))
    pokey.APokeySound_PutByte(c_int((chn+1) * 2), c_int(n//256))
    pokey.APokeySound_PutByte(c_int((chn+1) * 2 + 1), c_int(gen * 16 + amp))
    pokey.APokeySound_PutByte(c_int(8), c_int(0b00011000))

    out ='pokey.wav', 'wb')
    buf = (c_ubyte * 8192)()

    def wait(n):
    for i in range(n):
    size = pokey.APokeySound_Generate(114 * 312, buf, c_int(16))
    out.writeframes(array('B', buf[0:size]))

    for i in range(0,0x10000//40,1):
    dsound(0, i, 10, 15)

    Pitch detection:
    import aubio
    import numpy as np

    buf_s = int(44100*2/50)
    hop_s = int(44100*2/50)
    src = aubio.source('pokey.wav', hop_size=hop_s)
    print(src.uri, src.samplerate, src.channels, src.duration)
    samplerate = src.samplerate
    tolerance = 0.8
    pitch_o = aubio.pitch("yin", buf_s, hop_s, samplerate)

    total_frames = 0
    while True:
    samples, read = src()
    pitch = pitch_o(samples)[0]
    confidence = pitch_o.get_confidence()
    total_frames += read
    print (pitch, aubio.freq2note(pitch))
    if read < hop_s: break
    • 19:
    • CommentTime31 Jul 2020
    You could sample the true atari output to .wav file and decode frequencies using a similar method.
    Thanks for this! I think for now I am still going to rely on my ears ... once this is finished though, you all can maybe double check it all and see how it matches up. Some of these new settings are going to need new formulas.

    Meanwhile: I have learned how to convert my music into SAP, so I am going to start putting them onto ASMA. These are my first four contributions ... all using experimental SKCTL=$8B settings.

    Most SAP players won't do these, but I think they will work on the real Atari hardware. Please test ...
    • 21:
    • CommentTime1 Aug 2020
    IMHO (W)ASAP should support two-tone mode but apperently it doesn't work. Or is it?
    I found the problem.

    It is that WASAP doesn't like VBI being called, as I have done in my code. Apparently these are better suited to SAP-B, so I am trying to investigate how to modify these for SAP-B, it seems I need a timer in the code, something that uses VCOUNT. I am still trying to figure it out. :) Fairly new at this, sorry.
    • 23:
    • CommentTime2 Aug 2020 zmieniony
    For SAP TYPE-B there should be piece of code which you call every frame (or mutliples times a frame), and it should end with RTS. So that "throughway" one.
    I can confirm two tone mode $Ax distortion
    works in WASAP. Piotr helped me with converting two of mine into SAP-B. The Mario and Worldrunner ones, which both use $Ax plus SKCTL. I am going to try the Donkey Kong Country one next, that uses $4x distortion plus SKCTL for the guitars.
    • 25: CommentAuthorilmenit
    • CommentTime3 Aug 2020
    @pirx, super!
    My first two:

    Tempo on these is wrong, because I used NTSC duration, not PAL. They need to be fixed to play at right speed.

    Mario World Overworld: This one uses $Ax square @1.79 two-tone SKCTL mode. Play channel 0, silent channel 1. This is the famous "Save to Cassette" bell sound. :)

    3D Worldrunner: $Ax square @64 khz SKCTL for channel 0, channel 1 silent. Second channel has the melody, then you play first channel a fixed number of semitones above the first channel, to maintain pulse width.

    Tried on WASAP and it works. :)

    Going to try converting more ...
    • 27:
    • CommentTime4 Aug 2020 zmieniony
    OK, fixed timing for these two. TBH 3D Worldrunner works a bit better, Mario "knocks" sometimes instead of playing sound.
    Please check to see if the SKIPWRITEZERO code in Worldrunner is also in Mario. I may have forgotten to include it. There is some popping in the silent second channel also.
    Did another one ... it seems to work in Altirra. Also works in WASAP.

    This uses $4x distortion @1.79 mhz, in SKCTL mode. Again the timing is wrong (NTSC) ...

    I also fixed the note rests on the third channel. $0B makes silence on $Cx @1.79 mhz, not $0E

    How is the best way to correct the timings on it so that it plays at the right tempo?

    Also, noises and pops occur on the silent second channel. Is there a fix for this?
    I actually cleaned these up!

    Somebody on Atariage suggested this change and it worked!


    These should also be applied to worldrunner and mario as well. It kills the popping sound.

    Also: There are audible high frequencies on worldrunner and mario. These are all in third channel,$Cx @1.79mhz. All 14's in the duration table need to be changed to 11's, as these will make silence instead of high frequency noise.
    Mario World 1 and Worldrunner now updated, no pops. :) Also fixed the high frequencies. Good work ...
    And also this:

    Area 1/Area 3 theme from Zanac. This time, I used $Ax SKCTL with AUDCTL=$00, but I allow second channel to play on top of the first instead of silencing it. This transposes the melody down an octave and makes it into a 25% NES Pulse Wave. This method may make other interesting effects in other SKCTL settings.
    • 33:
    • CommentTime5 Aug 2020
    Great. If you want to change the timing into NTSC yourself just change "TYBE B" into the following sequence:
    TYPE B
    FASTPLAY 262
    Great! This helps alot ... :)
    OK, this is where I need help.

    I am attaching .xex and .asm sources.

    In this music, I am using SKCTL, these settings:

    AUDCTL=$20 (1.79 on third channel)

    0 - $Ax (SKCTL Two tone)
    1 - silent
    2 - $2x (1.79 mhz channel - triangle)
    3 - $Ax (standard square wave)

    The problem comes when I try to do note rests by using zero frequency. On $Ax channels this is no problem, 0 frequency cannot be heard by human ears, but in $2x, you can hear it. This also happens in $Ax at 15 khz mode as well.

    What is needed is code modification so that all zero's in the frequency table automatically get silenced. Does anybody have any ideas? Thanks ...
    Updated note table:

    Corrected the 15 khz settings on page 1 and page 4 of this .xls (thanks, jhusak!) with the proper frequency values. Again, calibrated to NTSC, the PAL ones should not be hard to calculate.

    There's still a couple of documentation errors on $4x distortions at 1.79 mhz, but will fix this with the next update. Also still working out some tables for hi-pass mode, and the $4x SKCTL mode.
    I have also sorted out the zero frequency problems on distortion $2x ... will post updated code soon as I can ... been real busy at work. :)
    The other interesting experiment is with $Cx mod 3 smooth bass settings in 16-bit. I believe pavros came up with a method to stabilize these tones by using 3rd pokey channel and resetting polycounters, but this is for standard 8-bit AUDCTL=$00.

    For 16 bit, because third channel usage is impossible, one will have to use frequencies divisible by 6 for one waveform, and frequencies divisible by 3 but not 6, for the other one. This is combined with the polycounter reset before each note play. I will experiment and modify the note table accordingly.
    Dzięki. Każda metoda byłaby pomocna.

    I am still going through the course on Duolingo and I am having a hard time keeping vocabulary. I have some of the grammar down but can't remember my noun cases well (like this: Woda jest fajna. Piję wodę. Jestem wodą. Idź do wody.) I had to use the translator to get the endings for woda. :) Hard to remember these ...

    I did Swedish on duolingo and I am about A2 on it now. But Swedish is easy for English speakers. My Spanish is about the same too. But Polish is important!
    • 40:
    • CommentTime30 Aug 2020
    English is my native language. I have some familiarity with latin and germanic languages, so it may help some. My main difficulty is in remembering vocabulary, and the case endings. I will keep trying.
    I had a question about my .s code I use to make the tunes. I want to make it so that it can play stereo POKEY, 8 channels. I know I have to put in extra equates, but looking for some help as to how to address those extra channels in my code ... that is, $04 to $07 in CHANNLTBL to get the extra sound channels.
    New development:


    AtariAge user Ivop has written a program for exploring undocumented POKEY modes. Covers all AUDCTL settings and SKCTL two tone mode. This will cut down on my work.

    It may be even possible to dump an entire setting to wave files and analyze them with FFT software to generate note tables.
    • 44:
    • CommentTime24 Sep 2020 zmieniony
    This is exactly what I suggested before, the skeleton implementation doing exactly this above :)
    It is just a few lines of code in Python.
    Best news is, I have figured out a pattern on some of these settings, which means we don't have to do all 65,536 frequencies for some of these

    The audio tool written by ivop is in advanced beta release. You can now sweep frequencies, then get a windows tool called aubiopitch to analyze and dump out frequencies for each setting. This will make my task much easier!


    This thread also has a link to aubiopitch. So, run this program in Altirra, get the setting you want, set Altirra to record, set warp speed emulation, then start the frequency sweep. Give the .wav file that is recorded, to aubiopitch to process. :)

    If you want to record PAL frequencies instead of NTSC, set Altirra to PAL emulation mode before doing the above steps.
    So here is the full release of the Pokey Explorer:


    This tool lets you explore different settings, and you can also set frequency sweeps which can then be recorded in Altirra emulator, and ran through aubiopitch on Linux to decode to actual frequencies. :)

    Already working on AUDCTL=$64 1.79+1.79 using $Ax and $2x distortions. $Ax makes nice sawtooth waves.
    A preliminary note table ...

    AUDCTL=$64 (double 1.79 clock) with AUDC1=$Ax and AUDC3=$00

    This makes sawtooth waves.

    There are 5 intervals that we play with ... based on prime numbers 1, 2, 3, 5, and 7

    At 1, the frequency values differ from each other in AUDC1 and AUDC3 by +/-1

    The other prime numbers increase the differential, and allow accuracy in higher notes, but put in a high pitch overtone in lower notes.

    I have so far a note table for interval 1 only. I will add other intervals soon, and that will make the note table more in tune.

    Note: Reversing the 16-bit number ($bbbc to $bcbb) makes the same note but turns it into a backwards sawtooth.

    Tuning errors start at c6, at c7 notes are dropped from the table. The other prime intervals may fix this, hopefully.

    NTSC values only. Will try to convert to PAL next


    Table 1: $0101 interval, forward sawtooth

    c1 - $e5e6
    c# - $dfe0
    d - $d8d9
    d# - $d2d3
    e - $cacb
    f - $c6c7
    f#1 - $c0c1
    g - $bbbc
    g# - $b5b6
    a - $b0b1
    a# - $aaab
    b - $a6a7

    c2 - $a1a2
    c# - $9c9d
    d - $9899
    d# - $9495
    e - $8f90
    f - $8a8b
    f# - $8788
    g2 - $8384
    g# - $7F80
    a - $7B7C
    a# - $7778
    b - $7475

    c3 - $7071
    c# - $6D6E
    d - $6A6B
    d# - $6768
    e - $6465
    f - $6162
    f# - $5e5f
    G - $5B5C
    g# - $5859
    a - $5657
    a# - $5354
    b - $5152

    c4 - $4E4F
    c# - $4c4d
    d - $4a4b
    d# - $4748
    e - $4546
    f - $4344
    f# - $4142
    g - $3f40
    g# - $3d3e
    a - $3b3c

    a# $393a
    b - $3839

    c5 - $3637
    c# - $3435
    d - $3233
    d# - 3132
    e $3031
    f $2e2f
    f# - $2d2e
    g - $2b2c
    g# - $2a2b
    a - $2829
    a# - $2728
    b - $2526

    c6 - $2425
    c# - $2324
    d - $2223
    d# - $2122
    e - $2021
    f - $1f20
    f# - $1e1f
    g - $1d1e
    g# - $1c1d
    a -$1b1c
    a# - $1a1b
    b - $191a

    c7 - $1819

    d7 - $1718
    d# - $1617
    e -
    f - $1516
    f# - $1415
    g - $1314

    a - $1213
    a# - $1112

    c8 - $1011
    • 49:
    • CommentTime26 Oct 2020


    I am still going through the course on Duolingo and I am having a hard time keeping vocabulary. I have some of the grammar down but can't remember my noun cases well (like this: Woda jest fajna. Piję wodę. Jestem wodą. Idź do wody.) I had to use the translator to get the endings for woda. :) Hard to remember these ...

    Wow! Impressive! Nice to meet such an open-minded person.
    OK, I think I have fully documented AUDCTL=$64 AUDC1=$Ax AUDC3=$00

    So this lets you produce the NES style triangle wave. As you go to lower frequencies, a noise artifact is introduced. As you go higher, the apparent volume gets lower.

    There exist the following intervals:

    Starting frequency ... interval
    $0001/$0100 $0101
    $0002/$0200 $0202
    $0205/$0502 $0303
    $0106/$0601 $0505
    $030A/$0A03 $0707

    Frequency is listed as AUDF1/AUDF3 ...
    Second starting frequency is for inverse triangle waves
    Interval is the incrementation of AUDF1 and AUDF3

    Intervals use prime numbers (1,2,3,5, and 7. Prime numbers above these such as 11 and 13 are not particularly useful)

    Below is a table which optimizes the frequency for all intervals. To make the inverse triangle wave, reverse the frequency settings (for example $e5e6 becomes $e6e5) ... except frequencies that have a * use the $0505 interval, in which case the inverse frequency is listed (for example c#4 is $abb0, and $b5b0 inverse).

    These are NTSC values. I will recalculate for PAL next. Feel free to test these out. :) Dzieki!

    AUDCTL=$64 AUDC1=$Ax AUDC3=$00 NTSC

    c1 - $e5e6
    c# - $dfe0
    d- $d8d9
    d# - $d2d3
    e - $cacb
    f - $c6c7
    f# - $c0c1
    g - $bbbc
    g# - $b5b6
    a - $b0b1
    a# - $aaab
    b - $a6a7

    c2 - $a1a2
    c#2 - $9c9d
    d2 - $9899
    d#2 - $9394
    e2 - $8f90
    f - $8b8c
    f#2 - $8788
    g - $8384
    g# - $7f80
    a - $7b7c
    a# - $7879
    b - $7576

    c3 - $7172
    c# - $6d6e
    d - $6a6b
    d# - $b6b9
    e - $6465
    f - $adb0
    f# - $5e5f
    g - $5b5c
    a - $7a7c
    a# - $5354
    b - $9295

    c4 - $4e4f
    c# - $abb0* / $b5b0
    d - $6a6c
    d# - $6668
    e - $4546
    f - $4344
    f# - $4142
    g - $3f40
    g# - $585A
    a - $8388* / $8d88
    a# - $5456
    b - $5052

    c5 - $3637
    c# -$3435
    d - $4a4c
    d# $3132
    e $3031
    f $2e2f
    f# $5053
    g $4D50
    g# $737A
    a - $2829
    a# - $6C73
    b - $2627

    c6 - $5156* / $5b56
    c# - $3436
    d - $4C51* / $5651
    d# - $2122
    e - $474C* / $514c
    f - $575E
    f# - $2c2e
    g - $3538
    g# $1c1d
    a - $282a
    a# - $1b1c
    b - $383d* / $423d

    c7 - $191a
    c# - $1819
    d - $2224
    d# - $292c
    e - $2022
    f - $1516
    f# - $1415
    g - $292e* / $332e
    g# - $1c1e
    a - $1213
    a# - $1c1e
    b - $2429* / $2e29

    c8 - $6170
    c# - $1d20
    d - $0f10
    d# - $1f24*/ $2924
    e - $0e0f
    f - $1a1d
    f# - $0d0e
    g - $3086
    g# - $171A
    a - - $0405
    a# - $0b0c
    b - $0a0c

    c9 - $1417