9

I’ll clarify what I mean. The sound chip (c64's SID, spectrum's Yamaha, etc.) is connected either to the input / output port, which will be reserved for the sound chip, or directly to the CPU data bus.

Let's say the sound chip is connected to the port. And let's say that the CPU is 8086/8088.

It turns out that for the chip to play music, I need to submit the assembler commands of this sound chip to sound chip from the assembler commands of the CPU. And this must be done at regular intervals.

Something like (x86 pseudo asm) :

byte db portSound 2
byte db musicPart1 0x5A //asm command of sound chip
byte db musicPart2 0x2C
byte db musicPart3 0x10

out portSound, musicPart1 
//here delay 1
out portSound, musicPart2 
//here delay 2
out portSound, musicPart3
//here delay 3

etc

So, is there a base in which for a sound chip I can find music for it in the form of assembler commands for this chip?

P.S. I mean source code for real music, and not just a single tone sounds/melodies like for the buzzer in Arduino.

P.S.S. I searched google for the information itself. Finding music in different formats is not a problem. Playing it on a PC is also not a problem. If the music format contains commands for the sound chip, it means that it must also contain delays (for a reading program on a PC). It turns out that I should just find the music in the right format, open it in the hex editor and take out byte by byte, according to the format description?

3
  • 1
    Nit: CPUs and sound chips don't have "assembler commands". An assembler is a program that produces (in the CPU case) machine code, which is what the CPU does understand.
    – dave
    Commented Aug 22, 2019 at 11:52
  • 1
    At least the SID doesn't execute anything. It has registers for controlling frequencies, ADSR parameters, waveforms, start and stop of a "note", etc ... and you have to write them in "real time" for playback. Commented Aug 22, 2019 at 14:40
  • 1
    This is a lot more complicated than what I had for my Exidy Sorcerer around 1979. There was a guy in Idaho selling hand-crafted circuit boards for sound that plugged into the parallel port. I bought it with his "Piano Player" software (a guy seated at a piano would play timed with the music). The music source was regular sheet music. There was an editor in which you input the music, and then you could play it with 4-voice polyphonic sound. It was more advanced than fancier-looking music generators for most other computers, even years afterward.
    – RichF
    Commented Aug 22, 2019 at 16:37

6 Answers 6

24

From your source code, it looks like you're expecting to be able to find individual songs as standalone assembly listings for a 'master' CPU (such as your 8086) that you can execute to play a song on a sound chip. Outside of very small examples, that's not a very useful way to use a sound chip, since unless the song code is designed like a coroutine, you won't be able to do anything else while the song is playing. (1)

(An earlier version of this answer misread your source code, apologies.)

In a game, the more common usage is to have a music playback routine separate from the song data, called at regular intervals to interpret a data-dense music binary format, to send instructions to the sound chip on every 'tick'. This routine is often referred to as a 'tracker', 'player', 'monitor' or 'playroutine' (2). This is what I think you're looking for.


Short answer:

For an example of a complete game written in Z80 assembly for the Sega Master System that has a music player routine and binary music format, you can look at the source to Gravity Beam: Master Gaiden (MIT licensed). Disclaimer: I wrote it. :)

You can listen to the music on YouTube.

The music binary blobs are stored in musicmodule_*.bin, and the playback routine is in audio.z80asm. My routines are heavily commented, so you'll be able to see a typical way to control a SN76489 sound chip from within a game running on a Z80. (3)


Long answer, and why your question isn't straightforward to answer:

In a game, music playback would be controlled by a music library on the master CPU, with its own state machine in memory wrapping the hardware state machine of the underlying sound chipset. The role of the music library would be to abstract the sound chip and present simpler routines for the game code to use. It would hold all of the state regarding the current song, current song position, volume, etc. The music library would have entry points like: music_select_song:, music_begin_playback:, music_pause:, music_set_volume:. The musical data itself lives in a separate binary blob.

The game would advance the music playback at regular intervals (4) by calling some music_advance: routine that would move some internal pointer along the current music track in memory, read the next bytes of data, identify what notes had been triggered or silenced, or what track parameters must be altered, and alter the state of the music chipset appropriately through OUT or memory mapped I/O. (5) If this sounds like the role of a MIDI player, well, that's because that's exactly what a MIDI player does. :)

On retro systems, music binary format standards were uncommon, and ROM and RAM space were at a premium so formats and trackers and players were often bespoke - written by the musicians themselves to easily expose whatever functionality they felt they needed, like Chris Hülsbeck & Peter Thierolf's TFMX format. Player routines could even add additional functions that the underlying hardware didn't have, which would have to be simulated by the routine as it proceeded through the song - things like pitch slides, rapid arpeggios (like the characteristic 'bubbling' SID sound) and warping/flanging from duty-cycle tricks. These would either be calculated in real time by the play routine (producing a pseudo-instrument sometimes known as a 'patch' or 'programme') or baked into a list of instructions by the editor (so effects like echo and reverb would be achieved by the editor simply adding additional quieter notes automatically into the note list).

In Gravity Beam: Master Gaiden, the binary music format is heavily packed to save ROM space, and the music player routine must analyse the bytes of the song to determine the delay until the next event, the track to alter, the pitch, and the patch to use (by itself the SN76489 doesn't have ADSR envelopes, so fading notes in and out must either be in-song instructions or part of the patch).

And every system is different, and ports of the same game across different 8-bit platforms might be written (quickly) by completely different people, the underlying music code could be totally different.

In the modern day, it's much easier to write something that would play an unmodified MIDI file on any system by interpreting the data in real-time, or translate a MIDI file off-line in advance to a more appropriate format for a given system. With better computers and communication, there are much more transparent standards and cooler tools and editors and off-line patch simulators for things like the YM2612.

So, anything is possible!

To be able to answer your question, you'd need to give us an example of what sound chip you're interested in. Then, we'd be able to identify tracker programs to edit common music formats for that chip, and suggest playback routines to go with it. Software like GoatTracker for the C64 (and its SID) and ProTracker for the Amiga (and its Paula) are editors that come with an assembly language playback routine you can use in your projects to play their songs. An example of a commercial music library used at the time would be Sega GEMS for the Mega Drive.

If you really want to make a standalone music player of the kind you describe (uninterruptible, no graphics ability, etc.), then you'll still need to tell us what system and what sound chip it ought to target. Some tracker editors can output a standalone playable listing like the one you want, like the BASIC-headered self-loading and self-executing SID files described in pjc50's answer. :)

  • Unless you're asking for 'all systems' and want a catalogue-like list of systems together with their most-common editor+playback pairs?

  1. An example of a situation where sound code and data would be interleaved is if you had very limited CPU and controlled some aspect of the chipset directly with asm commands to produce some effect. E.g. playing a digitised speech on a 48K Spectrum like in Ghostbusters. In Ghostbusters everything freezes while the shout is played, so I don't doubt there's a play_ghostbusters_speech: routine in there somewhere with amplitudes and delays all mixed up together.
  2. A 'tracker' more commonly refers to the editor for making tracker songs (ProTracker, OctaMED, GoatTracker etc.), but the playing routine is often called a 'tracker' too. A monitor is a term for a resident ROM/RAM program that lives in the background and can be invoked to describe the current state of a program. Since a music player lives in the background, it is occasionally called a monitor. SoundMon by Brian Postma is music player/editor on the Amiga found in games like Exodus 3010.
  3. Incidentally, since the Sord M5 / CGL M5 has the same sound chip and processor, I've had the same routine running on an M5 to play the same music (with a little accomodation for the different timing).
  4. This can also be called by an interrupt built into the system hardware, like a Master System VBlank interrupt, or a configurable timer.
  5. If you'd like to see what SN76489 'instructions' look like, you can see The SN76489 datasheet or the programming guide at SMS POWER.
2
  • 2
    There definitely exists one retro programmable sound chip that can hold a whole song program in memory, although it was only used by a video game console, not a computer: the SPC700 (used by the SNES). It is a 6502-flavored cpu combined with a fixed pipeline DSP. Given that one exists, there are probably more, although it definitely was not the most common design for sound chips, and is a lot newer than say the c64's sound chip. Commented Aug 22, 2019 at 13:44
  • @MattCarr If you create an account, you can make edits to your answer without them going through the review process; it'll be a lot easier for us. Then, if it hasn't automatically linked to this unregistered one, you can request the accounts to be merged using the contact form at the bottom of the page.
    – wizzwizz4
    Commented Aug 24, 2019 at 9:51
6

The "SID" file format is basically this, especially if you're using an actual SID. However it's an executable in 6502 assembly, so to run it on another architecture some work will be required.

Lots of MIDI music is also adaptable to run on various sound chips, although that will require you to set up the "instruments". This was popular with the "AdLib" synthesis cards for PCs.

6

To me this question is not really good because it cannot be properly answered. You really need to decide what specific chip/format/platform you want to focus on and read up. At the moment your ideas about how things might work show a clear lack of background research.

There are actually many sound chips, even many approaches to sound generation. If we are talking about retro sound chips - none of them use "assembler commands". They do not execute commands. Instead, they are specialized waveform generators, with various parameters fed to them by a player.

Changing parameters of the generators changes the sound, usually with an immediate effect. So the player works off an external timer to check what needs to be changed every once in a while and, when necessary, sends the relevant data to the sound chip. How this external timer works is again platform dependent. Some retro computers have system timers and can use them; many rely upon a video vertical blank interrupt to provide a regular timing event (this is why 50hz or 60hz timers are so common for the basic unit of time in retro trackers). Some retro computers do not have even that, so they have to resort to hand-tuned timing loops of various kinds.

Now, the players themselves also vary massively. Some of the players would store literal parameter values to be passed to the sound chip at every timer tick (such players are often called players of register dumps). Storing music in the form of register dumps is actually not popular, because they tend to require too much storage space for the music data. Hence, most players, in an attempt to save storage space, do substantial amount of processing while translating from tracker representations, or intermediate representations, into register values for the sound chip. So, simply reading tracker music representation in binary is going to be fairly hard, because such translation would require very detailed understanding of how tracker commands are going to be interpreted by the player.

5

There are many player programs with source code to play various formats for these chips. Many music files from e.g. DOS games for AdLib (Yamaha YM3812 chip) can be directly in register dump format or can be converted to one, such as DRO, IMF, RAW or VGM just to name a few. DosBox can save DRO files when a game is running.

4

I guess what you need is a file which contains a dump of the registers modified and at what time they were modified. Such dumps can be created, for example, from a SID file. Not much time ago, I updated a little program:

SIDDump V1.06 by Cadaver ([email protected]) and Stein Pedersen

That, esentially, is a C64 emulator, which can accept a SID file as an input, "play it" for a certain amount of time, and produce a binary dump file of values written to all registers every 20 miliseconds. http://www.zxuno.com/forum/viewtopic.php?f=47&t=491&p=16383#p16376

0

On the C64, there used to be a couple of "standard" sound formats. One(s) which only contained the sound data, including delays &c., to be interpreted by a seperate player program, and others which bundled the data with a corresponding player routine (usually in assembler) into a single file.

The 'embedded' playing routine usually provided a call address which would have to be called 50 (PAL) or 60 (NTSC) times per second to keep playing the sound. This "standard" way of handling allowed for easy playback in the background as it could simply be hooked up to a CRT interrupt firing once per frame, at a time where the sound processing would not block other critical processing, e.g. after the content for the next screen was prepared in the background buffer waiting to be displayed.

Not the answer you're looking for? Browse other questions tagged .