Jump to content
IGNORED

Music/Sound Programming Question (Atari 2600)


johnnye79

Recommended Posts

I'm learning about the Atari 2600's sound and have some questions regarding frequency, it has to do with shifting pitches.

 

How do I obtain the fundamental frequency of a note from the Atari 2600 that's sampled at 31400Hz, with a frequency (AUDF) divisor of 25 for each instrument so that I can shift them in pitch to piano notes?

 

(This is understandably a mix of programming, mathematics, and music theory, so I'm posting it here.)

 

So I've sampled small 8-bit Mono WAV files for each instrument (sampled at 31400Hz) with a divisor of 25 at their repetitions. So for example since instrument 8 has a repetition every 511 runs, I ran my Python code to output a wav of 26*511 samples (26 because count goes from 25 to 0) at frequency 25, and I've done this for each sound file so that I get a nice perfectly looping wav file.

 

My question comes down to how to understand what pitch that sample is at, so that I can shift its pitch to notes that are in tune with piano frequencies. I've tried doing some analysis on the samples in Audacity, but of course see frequency ranges all over the spectrum. So I suppose I need to understand how to attain the fundamental frequency of the sample so that I shift the pitch (this is easily done in OpenAL by specifying a float that determines the multiplier for scaling the pitch).

 

I've looked at the "Atari 2600 Frequency and Tuning Chart for NTSC" but that only seems to show some information about 5 of the instruments, I'm guessing the whole concept of "Setups" is specific to Paul Slocum's Synthcart, and I'm unsure how they came to the conclusion that a particular note from the 2600 was X number of cents above or below a certain note/octave.

Link to comment
Share on other sites

These are the frequencies I analyzed based on a Pitch Detection plugin for Audacity written in Nyquist. I don't know enough yet about Nyquist to see where in the code it's rounding off and truncating frequencies. Clearly it's rounding to the nearest Hz. I wonder if there's a better way to figure it out? I'd like to know those exact frequencies so I know how detuned an instrument is.

    const float *startingFrequencies[15] = {
        400.0f, // Sample 01
        13.0f,  // Sample 02
        172.0f, // Sample 03
        616.0f, // Sample 04
        616.0f, // Sample 05
        39.0f,  // Sample 06
        39.0f,  // Sample 07
        592.0f, // Sample 08
        405.0f, // Sample 09
        39.0f,  // Sample 10
        0.0f,   // Sample 11
        200.0f, // Sample 12
        200.0f, // Sample 13
        12.0f,  // Sample 14
        405.0f  // Sample 15
    };
Link to comment
Share on other sites

  • 3 weeks later...
It's been a while since I've looked at this subject, so I hope I've gotten all of the details correct!


You can use the following formula to calculate the frequency of a particular note generated by the TIA:


NoteFrequency = OscillatorRate / ColorClocks / WaveformLength / NoteValue


OscillatorRate is the frequency of the crystal oscillator, which determines the number of color clocks (a.k.a. pixel clocks) per second. This depends on the type of 2600:


NTSC 2600s: OscillatorRate = 3579575 Hz
PAL or SECAM 2600s: OscillatorRate = 3546894 Hz


ColorClocks is the number of color clocks per audio clock. The TIA generates 2 audio clocks per scan line, and there are 228 color clocks per scan line, so there are 114 color clocks per audio clock (228 / 2). This is really an average value, because one audio clock is 112 color clocks long and the other is 116 color clocks long, due to the way they're generated by the HSC (Horizontal Sync Counter). The horizontal clocks that drive the HSC are 4 color clocks long, so there are 57 horizontal clocks per scan line (228 / 4). We can't evenly divide 57 by 2-- the closest we can get to an even split is 28 and 29-- but it's just a coincidence that it worked out that well for the audio clocks. The HSC generates a number of events (or signals) related to the scan line and the playfield, and some of these are used to trigger the phases of the audio clocks. As luck would have it, two such events are separated by 28 horizontal clocks (or 112 color clocks, 28 * 4) in one direction and 29 horizontal clocks (or 116 color clocks, 29 * 4) in the other direction. In any case, we say that there are (on average) 114 color clocks per audio clock.


WaveformLength is the length of the waveform generated by the value written to the AUDC0 or AUDC1 register. (We'll ignore audio channel 1 for the rest of this discussion and focus on audio channel 0.) There are 16 possible values for AUDC0 (0 through 15), but some generate waveforms which are duplicates of other AUDC0 values, so there are really only 11 unique waveforms. The lengths of the waveforms are given as the number of samples in one complete cycle, which are as follows (sorted in ascending order by length):


AUDC0 = 0 or 11: waveform length = 1 ("always on")
AUDC0 = 4 or 5: waveform length = 2
AUDC0 = 12 or 13: waveform length = 6
AUDC0 = 1: waveform length = 15
AUDC0 = 6 or 10: waveform length = 31
AUDC0 = 7 or 9: waveform length = 31 (different than AUDC0 = 6)
AUDC0 = 14: waveform length = 93
AUDC0 = 15: waveform length = 93 (different than AUDC0 = 14)
AUDC0 = 2: waveform length = 465
AUDC0 = 3: waveform length = 465 (different than AUDC0 = 2)
AUDC0 = 8: waveform length = 511


NoteValue is the value written to the AUDF0 register, plus 1. There are 32 possible values (0 through 31), but we need to add 1 to them for our formula. To get a little bit technical again, the TIA uses tone clocks to control the rate at which a waveform is played. Each tone clock is generated by the AFD (Audio Frequency Divider) by suppressing some number of audio clock signals. The value of AUDF0 specifies how many sets of phase 1 and phase 2 audio clock signals to suppress. If AUDF0 = 0, no signals are suppressed, so 1 tone clock = 1 audio clock; if AUDF0 = 1, one set of signals is suppressed, so 1 tone clock = 2 audio clocks; if AUDF0 = 2, two sets are suppressed, so 1 tone clock = 3 audio clocks; etc. This has the effect of stretching the waveform to a multiple of its normal length, thereby dividing the waveform's normal or "base" frequency and producing a lower pitch.


So if you set AUDF0 to 25 on the NTSC 2600, the various values of AUDC0 should produce the following frequencies (rounded to 5 decimal places):


AUDC0 = 0 or 11: NoteFrequency = 3579575 / 114 / 1 / 26 = 1207.68387 Hz (but the samples are "always on" so you get no sound)
AUDC0 = 4 or 5: NoteFrequency = 3579575 / 114 / 2 / 26 = 603.84194 Hz
AUDC0 = 12 or 13: NoteFrequency = 3579575 / 114 / 6 / 26 = 201.28065 Hz
AUDC0 = 1: NoteFrequency = 3579575 / 114 / 15 / 26 = 80.51226 Hz
AUDC0 = 6 or 10: NoteFrequency = 3579575 / 114 / 31 / 26 = 38.95754 Hz
AUDC0 = 7 or 9: NoteFrequency = 3579575 / 114 / 31 / 26 = 38.95754 Hz
AUDC0 = 14: NoteFrequency = 3579575 / 114 / 93 / 26 = 12.98585 Hz
AUDC0 = 15: NoteFrequency = 3579575 / 114 / 93 / 26 = 12.98585 Hz
AUDC0 = 2: NoteFrequency = 3579575 / 114 / 465 / 26 = 2.59717 Hz
AUDC0 = 3: NoteFrequency = 3579575 / 114 / 465 / 26 = 2.59717 Hz
AUDC0 = 8: NoteFrequency = 3579575 / 114 / 511 / 26 = 2.36337 Hz


To make it easier for you to compare these with the values in your second post, here they are in ascending AUDC0 order:


AUDC0 = 0: NoteFrequency = 1207.68387 Hz (but it's actually silent)
AUDC0 = 1: NoteFrequency = 80.51226 Hz
AUDC0 = 2: NoteFrequency = 2.59717 Hz
AUDC0 = 3: NoteFrequency = 2.59717 Hz
AUDC0 = 4: NoteFrequency = 603.84194 Hz
AUDC0 = 5: NoteFrequency = 603.84194 Hz
AUDC0 = 6: NoteFrequency = 38.95754 Hz
AUDC0 = 7: NoteFrequency = 38.95754 Hz
AUDC0 = 8: NoteFrequency = 2.36337 Hz
AUDC0 = 9: NoteFrequency = 38.95754 Hz
AUDC0 = 10: NoteFrequency = 38.95754 Hz
AUDC0 = 11: NoteFrequency = 1207.68387 Hz (but it's actually silent)
AUDC0 = 12: NoteFrequency = 201.28065 Hz
AUDC0 = 13: NoteFrequency = 201.28065 Hz
AUDC0 = 14: NoteFrequency = 12.98585 Hz
AUDC0 = 15: NoteFrequency = 12.98585 Hz


Some of these are sort of close to the values you got, but some are way off, which I'll explain below. As for the ones that are sort of close, I'm not sure I understand what you did-- did you sample the actual output of the NTSC 2600, or did you write a program to generate your own samples? In any case, 31400 Hz is just an approximation of 3579575 / 114, so any calculations that use 31400 Hz are going to be a little off.


But what about the values that are way off? It turns out that the frequencies calculated with our formula don't necessarily reflect what you actually hear when the notes are played. This is due to each waveform's pattern. If the waveform has a single high phase and a single low phase, we say that it produces a "pure tone." This isn't entirely true, because the waveforms aren't sine waves and often their high and low phases aren't equal in length; but for the most part any harmonic overtones are quiet enough that these "pure tone" waveforms do sound a lot like sine waves. However, if a given waveform has more than one set of high and low phases it will produce noticeable harmonic overtones, hence what we hear will generally sound like some multiple of the calculated frequency. I'll go into this later in another post.
  • Like 1
Link to comment
Share on other sites

The pure channels mentioned above 12 & 4 have these notes (shown overlapped).

The Buzzy & Pure Buzzy can fill in some missing pure notes if played quieter.

Also, see G4 is missing? G4 can be AUDC0=12: AUDF0=12. I guess it is omitted because it is very off key? But I've used it.

Ch=8 is sssshhh through low explosion, used for percussion, along with other low tones.

 

med_gallery_29575_733_35842.jpg

 

Then there is the 3-channel DPC method, which can be done just in programming, but that uses a lot of CPU so the Pitfall II method is best done in-game with the DPC or DPC+ implementation. It is done is Stella Stocking in software as the title screen music. "Better Than Pitfall" does 4 channels in software.

A simple explanation is that it is similar to sound samples, but it generates perfect pitch tones by vibrating the speaker using only the volume register AUDV0 and/or AUDV1, which is in (or silent) at 0, or pushed all the way out at 15. Changing the data values every or every other scan line through the whole display and overscan and vertical blank can give 3 or 4 notes per channel.

 

sf2musicShepherdsROUND.bin

Link to comment
Share on other sites

I'm all about sound, but unsure what you are trying to do.

There is the detailed operation above of what the hardware is doing to produce sound.

That results in the 319 tones and noises you can use in the 2 channel output for notes and percussion.

 

That's my business mate. ;)

 

Kidding.

 

It would be great to know in making a ***NON-COMMERCIAL*** open source VSTi (translated: I'm here for the good of the community), also some hardware projects I'm doing with embedded microcontrollers (STM32 NUCLEO F103RB for example) for neat sound effects, playing music, etc. I understand TIATracker exists, but TIATracker looks like it's for playing music on an Atari cart. Plus, I like to learn things, plus, there's a lot of practical applications I can think of right now for various projects.

 

I want to get Atari notes in tune with normal piano frequencies by changing the pitch/speed to get them in tune (this can be done procedurally in OpenAL just by changing pitch parameters on a looping sample (1.0 plays at normal frequency, 1.054467467 plays higher, 0.9543954 plays lower, etc), trying to do it with a wav file in Audacity though seems to only go to 3 decimal places).

 

So far I've used a pitch detection plugin in Audacity to detect the pitches, it uses a YIN algorithm (the plugin is written in Nyquist so a lot is left behind the scenes, I'm looking at a pure C/C++ implementation), and I'm not 100% sure of its accuracy. There are other pitch detection algorithms I'll probably have to look at to determine the best one.

 

In your picture above what was the method used to determine how many cents a note is off? Is there a mathematical method to it or is that all done by ear? (I'm not implying that one method is better than the other, after all, it all comes down to what sounds pleasing to the ear.)

 

Why are some of the instruments missing in the above picture? (2, 3, 8, those are some of the best Atari instruments!)

 

Last bit is trying to figure out how to make a 31400Hz clock in C++ for mbed for audio output, which has proven a little cumbersome since you only get up to microsecond resolution, so I'll have to figure out a clock based on CPU cycles (I have some 72Mhz and 180Mhz STM32s), but that's a side issue.

Edited by johnnye79
Link to comment
Share on other sites

Semitones_From_A4 = 12 * LOG ( Frequency / 440, 2 )


Cents_From_Note = 100 * ( Semitones_From_A4 - ROUND ( Semitones_From_A4, 0 ) )


Edit: I'm working on posting a spreadsheet I made that simulates how the TIA generates its audio signal as shown in the schematics. I'm not going to explain it in detail, but I'll post a copy of the schematics that shows how the columns of the spreadsheet relate to the symbols on the schematics, along with some general comments about how to "use" the spreadsheet. I'll also post some other stuff related to TIA audio. This will likely be done in a series of posts, rather than all at once, and I'm going to be extremely busy with family for the next week, so it might take a little while. :)
Edited by SeaGtGruff
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...