psxsdk

CD audio

A PlayStation disc is a CD, and after its data track it can carry tracks of ordinary CD audio, the same as a music CD's. The drive plays them by itself and sends the sound straight to the SPU, which mixes it with whatever the program is playing, so music from the disc costs the program nothing: no memory, no CPU, and none of the SPU's 512 KB. It costs disc space instead, 176 KB a second of CD-quality 44.1 kHz stereo, which a game had plenty of. Games kept their music on the disc and their sound effects in the SPU.

The Net Yaroze could only boot its own disc, so the SCEE tutorial's CD chapter played whatever music CD was in the drive. A disc built here can carry its own tracks.

Declaring the tracks#

A program declares each track with disc.Track, as it declares a file with disc.Register, with the WAV file the track is made from:

var track1 = disc.Track("audio/TRACK1.WAV")

var track2 = disc.Track("audio/TRACK2.WAV")

var track3 = disc.Track("audio/TRACK3.WAV")

The build records each one after the data track, in the order the program declares them, and writes each track's number into the program, which TrackNumber returns. The WAV is 44.1 kHz, 16-bit stereo, as a CD's audio is. mkpsxiso puts the standard two-second pause before each track, which is where the drive's play starts when the library asks for a track by number.

Playing#

CdPlay plays from a list of track numbers ending with a zero: mode 1 plays from one of them to the end of the list, mode 2 round and round, mode 0 stops, and mode 3 only asks. Each returns which of the list is playing, or -1:

func main() {
	screen.Open()
	screen.Font(16, 16, 288, 200, 512)
	text.Init(textBuf[:])
	tracks = [4]int32{track1.TrackNumber(), track2.TrackNumber(), track3.TrackNumber(), 0}

	// The disc's audio is mixed into the SPU's output at full volume.
	yaroze.SsSetMVol(127, 127)
	yaroze.SsSetSerialAttr(yaroze.SS_CD, yaroze.SS_MIX, yaroze.SS_SON)
	yaroze.SsSetSerialVol(yaroze.SS_CD, 127, 127)

	for i := range bars {
		bars[i] = yaroze.GsBOXF{X: 40 + int16(i)*90, Y: 200, W: 60, H: 8, R: 60, G: 120, B: 120}
	}

	for ot := range screen.Frames() {
		pad.Update()
		switch {
		case pad.Pressed(yaroze.PADLleft) && chosen > 0:
			chosen--
		case pad.Pressed(yaroze.PADLright) && chosen < 2:
			chosen++
		case pad.Pressed(yaroze.PADRdown):
			yaroze.CdPlay(1, &tracks[0], chosen)
		case pad.Pressed(yaroze.PADRup):
			yaroze.CdPlay(2, &tracks[0], chosen)
		case pad.Pressed(yaroze.PADRright):
			yaroze.CdPlay(0, &tracks[0], chosen)
		}
		playing = yaroze.CdPlay(3, &tracks[0], 0)

		text.Reset()
		text.WriteString("~c099CD AUDIO~c999\n\n")
		for i := range int32(3) {
			if i == chosen {
				text.WriteString("> ")
			} else {
				text.WriteString("  ")
			}
			text.WriteString("TRACK ").WriteInt(tracks[i]).WriteString("  ").WriteString(trackNames[i])
			if i == playing {
				text.WriteString("  ~c990PLAYING~c999")
			}
			text.WriteString("\n")
		}
		text.WriteString("\nCROSS PLAYS FROM THE CHOSEN TRACK\nTRIANGLE PLAYS ROUND AND ROUND\nCIRCLE STOPS\n")
		text.Print()

		// A bar for each track, lit while it plays and pulsing with the
		// frames.
		for i := range bars {
			b := &bars[i]
			if int32(i) == playing {
				pulse := uint8(screen.Frame() % 32 * 4)
				b.R, b.G, b.B = 255, 160+pulse/2, 40
				b.H = 8 + uint16(pulse/8)
			} else {
				b.R, b.G, b.B = 60, 120, 120
				b.H = 8
			}
			b.Y = 208 - int16(b.H)
			b.Sort(ot, 0)
		}
	}
}

The SPU mixes in the disc's sound only once it is told to, with SsSetSerialAttr for the CD's input and SsSetSerialVol for its volume, beside SsSetMVol for the whole of the SPU's output.

A track plays while the program reads nothing else from the disc. A game that loaded a level stopped its music, or loaded everything first, or kept a short piece in the SPU to play over the loading. The cdda example's three tracks are made by its gen program, a rising arpeggio, a falling note and a beat, a few seconds each:

The emulator plays CD audio in the browser and in tests, which is how the example's test checks the track it asked for is the one that sounds.