From time to time I design or start to code Synthesiser/ Sequencers. OPulence is one I'm currently toying with. I might not complete it (many of my projects don't complete, sorry), but here's an introduction to the design and a specific question about how to allocate memory for waveforms and sequences, for which I think the solution is:
Introduction
I've done a bit of feasibility analysis on what I think I can get out of a 128kB Mac's sound capabilities. It will have similar functionality to Studio Session, and I intend to use 2-operator FM sounds.
I think I can get 5 voices (giving me 6 to 7 note polyphony, a-ha!) + a 4 piece 'polyphonic' drum kit out of an original Mac. This is close to an OPL2 chip in percussive mode. Don't get your hopes up too much, a signal to noise ratio for its 8-bit DAC with 5 voices will be pretty poor (super-crunchy), but at least you'd be able to play more sophisticated music than a classic MOD player could.
Architecture
Each FM instrument uses up to 56x 128-byte waveforms, a set of 8 FM tones x 6 amplitudes (so we don't have to calculate volumes on the fly). Envelopes will appear to step crudely between tone and amplitude. We can have up to 5 voices, but a voice can by bi-tonal, namely the note and its 5th. This means practical pieces can contain a chord (using 2 voices) + bass, melody and counter-melody. A drum kit is an array of 32 waveforms indexed by a 5-bit value where each bit represents a percussive wave that can be on or off. Combinations of bits correspond to combinations of the waveforms. eg. if bit 0 is a tom and bit 2 is a hi-hat, the value 5 will trigger a waveform that combines both.
Sequences consist of patterns at the lowest level, so, first there's a set of patterns in memory. Then the 5 (or 6) tracks list the patterns to use in each track.
Interaction
It's an actual Mac app, but incredibly crude. I have a VBL function for playback, where some ideas are copied from the MOD player discussion, except, based on counting cycles assuming a net 6.5MHz CPU, I can get 5 voices + the drums out of it. I've written a playback routine, which would just be triggered by a menu option. Finally, I have an awful non-Macintosh function for converting text in an RPN-format into synthesiser sound/drum kit definitions and sequences.
The Problem
The problem is a classic Mac OS memory allocation issue. There's no VM, and only 80kB available. Sound definitions will actually only take 42x6x128b=27kB, so playback code and sequences must fit in 53kB. Sound definitions are built up as we go along, so the application won't know the memory requirements until the end. With modern computers that's not a problem, you'd just allocate memory as you see fit, but here it is a problem.
A classic Macintosh app's memory consists of:
{ MasterPointers[forHandles], HeapSpaceForCodeAndData[both pointer-based blocks and handles + code and resources], spare space, HandleBasedBlocksThatHaveBeenMovedHi, a gap, the stack, A5World, App global variables }
So, when we're compiling instruments and sequences, there will be a couple of code segments at the bottom and the data we're allocating (to handles in my case) will go above that. And that's a bit annoying, because memory might get a bit fragmented. Pre-allocating pointers won't work, because I might need to change what's allocated to instruments and sequences to make way for larger code segments, but moving segments high is likely to help me manage it better.
So, my initial thought was to allocate blocks in 256b..512b (which would work easily for wave forms); and link them as a simple linked list. Patterns are a bit more complex as I'd want blocks to contain an integral number of patterns as long as each one is >=256b. So, then I thought I'd take this approach:
So, the reason for the 256b unit is so that I can work out the maximum number of blocks I need and generate enough
But then I thought I'd take another approach, which is what I want to run past experienced Mac programmers. And this would be to pre-allocate all the memory I think I need; fill it with all the data I want, and then call
But I could be wrong.
macintoshgarden.org
SetHandleSize.Introduction
I've done a bit of feasibility analysis on what I think I can get out of a 128kB Mac's sound capabilities. It will have similar functionality to Studio Session, and I intend to use 2-operator FM sounds.
I think I can get 5 voices (giving me 6 to 7 note polyphony, a-ha!) + a 4 piece 'polyphonic' drum kit out of an original Mac. This is close to an OPL2 chip in percussive mode. Don't get your hopes up too much, a signal to noise ratio for its 8-bit DAC with 5 voices will be pretty poor (super-crunchy), but at least you'd be able to play more sophisticated music than a classic MOD player could.
Architecture
Each FM instrument uses up to 56x 128-byte waveforms, a set of 8 FM tones x 6 amplitudes (so we don't have to calculate volumes on the fly). Envelopes will appear to step crudely between tone and amplitude. We can have up to 5 voices, but a voice can by bi-tonal, namely the note and its 5th. This means practical pieces can contain a chord (using 2 voices) + bass, melody and counter-melody. A drum kit is an array of 32 waveforms indexed by a 5-bit value where each bit represents a percussive wave that can be on or off. Combinations of bits correspond to combinations of the waveforms. eg. if bit 0 is a tom and bit 2 is a hi-hat, the value 5 will trigger a waveform that combines both.
Sequences consist of patterns at the lowest level, so, first there's a set of patterns in memory. Then the 5 (or 6) tracks list the patterns to use in each track.
Interaction
It's an actual Mac app, but incredibly crude. I have a VBL function for playback, where some ideas are copied from the MOD player discussion, except, based on counting cycles assuming a net 6.5MHz CPU, I can get 5 voices + the drums out of it. I've written a playback routine, which would just be triggered by a menu option. Finally, I have an awful non-Macintosh function for converting text in an RPN-format into synthesiser sound/drum kit definitions and sequences.
The Problem
The problem is a classic Mac OS memory allocation issue. There's no VM, and only 80kB available. Sound definitions will actually only take 42x6x128b=27kB, so playback code and sequences must fit in 53kB. Sound definitions are built up as we go along, so the application won't know the memory requirements until the end. With modern computers that's not a problem, you'd just allocate memory as you see fit, but here it is a problem.
A classic Macintosh app's memory consists of:
{ MasterPointers[forHandles], HeapSpaceForCodeAndData[both pointer-based blocks and handles + code and resources], spare space, HandleBasedBlocksThatHaveBeenMovedHi, a gap, the stack, A5World, App global variables }
So, when we're compiling instruments and sequences, there will be a couple of code segments at the bottom and the data we're allocating (to handles in my case) will go above that. And that's a bit annoying, because memory might get a bit fragmented. Pre-allocating pointers won't work, because I might need to change what's allocated to instruments and sequences to make way for larger code segments, but moving segments high is likely to help me manage it better.
So, my initial thought was to allocate blocks in 256b..512b (which would work easily for wave forms); and link them as a simple linked list. Patterns are a bit more complex as I'd want blocks to contain an integral number of patterns as long as each one is >=256b. So, then I thought I'd take this approach:
NewHandle ;to allocate the longer block.
BlockMove ;to copy the old one to the new one.
DisposHandle ;to deallocate the old one.
MoveHHi ;to move it back.
So, the reason for the 256b unit is so that I can work out the maximum number of blocks I need and generate enough
MoreMasters accordingly. But I think that method would be slow and the linked list would add a long handle-ref for each block which is a bit of a waste on a 128kB machine.But then I thought I'd take another approach, which is what I want to run past experienced Mac programmers. And this would be to pre-allocate all the memory I think I need; fill it with all the data I want, and then call
SetHandleSize to the actual block's size. So, my question is, when I call SetHandleSize to make the block shorter, will it (a) create another block to occupy the remainder or will (b) the memory manager just waste the remainder (so the physical size remains the same, but the logical one is smaller). I think that it's case (a) because if you increase the size of a handle, it will shuffle handle-based blocks around if possible to ensure the larger sized block can be properly resized. And I guess that my proposed use of SetHandleSize is exactly the kind of use-case they were trying to support.But I could be wrong.
MIDIMAC Sequencer 2.5 - Macintosh Garden
MIDIMAC Sequencer v2.5 is an early MIDI sequencer for the Macintosh, and a direct predecessor to Opcode's Vision. DL #1 This download is reconstructed from the contents of the original diskette. It is provided as a bootable 400k DiskCopy 4.2 disk image, compressed using StuffIt 1.5.1, and...

