An open API service indexing awesome lists of open source software.

https://github.com/tokenrove/ymamoto

A replay routine for the Atari ST, using the YM2149 chip.
https://github.com/tokenrove/ymamoto

Last synced: 11 months ago
JSON representation

A replay routine for the Atari ST, using the YM2149 chip.

Awesome Lists containing this project

README

          

YMamoto Alpha Zero
Julian Squires / 2004

ABOUT YMAMOTO

YMamoto is my first attempt at a reasonable music playroutine for the
Atari ST. The design goal is to allow the production of interesting
music; I considered adding efficiency of {memory usage, song size,
cycles per frame} to the set of goals, but I decided that aiming at
any of these things directly would just cripple the main goal, until I
am more familiar with the ST and the YM.

So, YMamoto, when finished, should be suitable at least for music
disks and parts of demos where cycles aren't too scarce.

USING YMAMOTO IN ANOTHER PROGRAM

Call ymamoto_init with A0 pointing to the song data, and D0 set to the
track index to play. Note that the first track index is 1, not 0.

Call ymamoto_update once per frame until it returns $FFFF in D0.

FIXME: Eventually there will be a way to use trigger events to allow
you to sync your effects to the music.

YMAMOTO DATA FORMAT

All relative pointers are to long aligned addresses, and hence the
pointers are stored as shorts, and shifted left two bits to get the
actual address. These pointers are relative to the beginning of the
song data, not their current position, and are always forward
references, so they don't get sign extended when loaded from words.

SONG

pointer to arpeggio table (word, relative, >>2)
pointer to volume envelope table (word, relative, >>2)
pointer to vibrato table (word, relative, >>2)
number of tracks (byte)
Should always be >=1.
offset to track 0 (word, relative, >>2)
offset to track ...

TRACK (long aligned)

channel A start point (word, relative, >>2)
channel B start point (word, relative, >>2)
channel C start point (word, relative, >>2)

CHANNEL DATA STREAM (long aligned)

The two kinds of values possible in the channel data stream are notes
and commands. They can be determined by the value of their MSB, which
is 0 for notes, and 1 for commands.

Notes are stored in the following inefficient way:
0ddd dddd rnnn nnnn
d => duration, in frames-1, from 0 (1/50th of a second)
to 127 (2.56 seconds).
r => reserved (0).
n => tone, value from 0 = C0, 95 = B7.
126 = wait, 127 = rest (wait, silence channel).
Other values might be used for special purposes.

Global commands: (can occur in any channel; need only occur once)
10rr rccc xxxx xxxx
r => reserved.
c =>
every track must end \ 000 => track end (not followed by any data)
with one of these. / 001 => track loop
010 => trigger external event
x => command data

Channel commands:
11cc cccc xxxx xxxx

1100 0001 aaaa aaaa
arpeggio. 0 = disable arpeggio.
1100 0010 xxxx xxxx
set detune
1100 0011 xxxx vvvv
set fixed volume
1100 0100 eeee eeee
set software volume envelope.
0 = disable soft envelope.
1100 0101 nnnn nnnn
enable/disable noise.
n = noise frequency, 0 to disable.
1100 0110 xxxx xxxx
AM sample playback [reserved.]
1100 0111
set hardware envelope [reserved.]
1100 1000 xxxx xxoe
envelope-follow mode.
e = enable/disable;
o = one octave lower/same pitch.
1100 1001 pppp pppp
pitch envelope. 0 = disable pitch envelope.
1100 1010 ssss ssss
portamento. s = speed.
1100 1011 vvvv vvvv
vibrato. 0 = disable vibrato.

Arpeggio and venv tables: (long aligned)

number of entries in table (byte)
entry 1 length (byte)
entry 1 loop point (byte)
entry 1 data (length*byte)
...

Vibrato table: (long aligned)

number of entries in table (byte)
entry 1 "length" (byte, always 3)
entry 1 delay (byte)
entry 1 depth (byte, 0 through 8)
entry 1 speed (byte, 0 through 4)
entry 1 oscillator mask (byte, 1< 1 = tied with next note
D => duration modifier:
000 => normal
001 => dotted
010 => double dotted
100 => triplet time
(quintuplet time? duplet time?)
NB that these may change from independant flags
into a single, 8 state value.
d => duration, value from 0 (whole note) to 7 (128th note).

Another thing is that, if we find we're already doing full divisions
somewhere (because of quintuplets or whatever), we might as well just
start representing durations as arbitrary fractions; this allows much
more flexibility in some ways.

MISC.

It could be interesting to provide a sort of voice scheduling system,
which tried to fit ``optional'' voices in on channels when the regular
voice was silent (due to rests or staccato). Maybe this is better
placed in the music composition tool, though.