• Hello MLAers! We've re-enabled auto-approval for accounts. If you are still waiting on account approval, please check this thread for more information.

DTMF Player

Snial

68000
Hi folks,

I haven't done any Sound development for Classic Mac OS, but I thought that writing a simple DTMF (UK DTMF) player would be fun.
PastedGraphic-1.png
This is my minimally functional version that works on a Mac Plus under system 7 down to a Mac 128kB on System 1 (If you Run DtmfSys1. You can type digits, ‘*’ and ‘#’ or type ‘-‘ to end a sound. You can click on the keypad to make a DTMF sound too (it stops when you let go). In System 7 it plays with periodic clicks, but under System 6 it's smooth. It's about 6kB on the disk and needs about 18kB in System 6 to run, but by default I've allocated 32kB for System 7 (haven't checked the minimum it'll run in).

It uses the Sound Driver in FourTone mode. Because DTMF tone frequencies aren't obvious multiples of each other, this approach makes far more sense than e.g. trying to create DTMF sound resources. Instead, I created a 256 sample Sine wave in Signed 0:15 fixed-point arithmetic (does everyone understand that?) by matrix multiplication. Conventionally that can be calculated as:

x'=x * Cos a - y * Sin a;
y'=x * Sin a + y * Cos a;

e.g. if we pick a=90º, then Cos a=0, Sin a=1; so [1,0] => [0,1] and [0,1] => [-1,0] which is correct.

In practice we need to pick 360º/256=1.40625º. So Sin a=0.02454, Cos a=0.9996988. In Signed 0:15 fixed-point that's 804 and 32758. As a side note, the fastest calculations can be done by calculating only 64 of the samples, and for each one you just reflect or negate to get the remaining quadrants (64 x 4 multiplies x 7µs each = 1.8ms).

At first I tried to follow the Inside Macintosh guide for using the Sound Driver, but in fact, it didn't seem to work at all! So, then I looked up all the MacTech articles on generating sound and found this one:

http://preserve.mactech.com/articles/mactech/Vol.02/02.02/SoundMadeSimple/index.html

Basically the article explains StartSound doesn't work properly at all as described in Inside Macintosh, but if you go straight to the underlying Sound Drive Parameter Block based API it does work. It's important to go for the early articles so that the APIs you use are likely to work with early Macs and OS versions. There's a whole bunch of Sound articles in MacTech. Perhaps I'll explore more of them in the future, because I might need a better sound payback to avoid glitches under System 7.

It looks like I used a bunch of custom buttons for the keypad buttons, but I didn't. I wanted to be able to figure out which keypad button was hit in one go, straight from the keypad grid & mouse coordinates. I used a pair of SICNs for pressed and released and invalidated only the button I wanted redrawn. The keypad digits are added to each button using DrawChar.

There’s space at the top for a full phone number and I’ll add a text box for that next. In theory, if you do audio out from a Mac to a UK landline and press digits it should phone the number, because they’re sine waves for UK DTMF at the right frequencies on a real Mac. (which might be the same as international DTMF, but I haven't checked). It runs in 32kB (it’s a 6kB program, doesn’t run in 16kB, but might run in 24kB). Running it in colour or on a PowerPC Mac might need a bit more.

Anyway, here’s the project and two versions of the app, one that uses WaitNextEvent for System versions that don't support GetNextEvent. I still haven't followed @David Cook 's guide on checking for that. There's also a few bugs: if the window is partially covered and re-exposed not all the buttons get properly redrawn. Also if you hold the mouse on one button, move it and let go on another, then the first keypad button remains highlighted.
 

Attachments

Good work. A 360 degree lookup table might be faster than reflecting/inverting.

If you're working with an 8-bit DAC, 0.15 fixed-point is excessive. Signed 8-bit samples of 63*Sin(x) will avoid clipping when the two voices are added.
 
Good work. A 360 degree lookup table might be faster than reflecting/inverting.
Probably my post wasn't so clear. I just created a 256 entry lookup table the long way, with 256 calculations. But it's done at run-time during initialisation as that makes for a shorter program. Once the table is filled, it's just used as is.
If you're working with an 8-bit DAC, 0.15 fixed-point is excessive. Signed 8-bit samples of 63*Sin(x) will avoid clipping when the two voices are added.
For Four Tone sound generation all the waveforms have to be unsigned 8-bit; but the 16-bit fixed point is useful, because it's pretty accurate when you do a final >>8 to get the top 8 bits for the waveform proper. The Four Tone sound driver adds 4 x 8-bit samples together and then does >>2. If I was filling the sound buffer directly with a dual tone, then yes, it's better to compute 63*Sin(a) as it saves a shift.

-cheers from Julz
 
You're having fun recently, aren't you :D.
Just to add to the last comment. I'm enjoying doing some vintage Mac programming - I'm enjoying the experience of writing GUI apps that can work in what amounts to the constraints of an embedded system, because you end up using many of the same techniques. Particularly, I enjoyed doing some work in MacASM, though my latest projects have mostly used ThinkC 5 as I have most of my experience with that.

My background is embedded systems and I can see how my interests took me in that direction since before I did my first BASIC programming course in 1980. At Uni (UEA) we were introduced to Mac 512Ks (& MacPascal/MacWrite/MacPaint) from the first term. So I had 3 years of that (+ a bit of VAX and Sun workstation stuff, whilst using a Sinclair QL in digs), but when I left UEA of course, the whole computing world went PC.

Therefore, unlike quite a number of people here, I've had decades of personal experience with Macs, but relatively little development experience with Macs. And amongst the many nice things about vintage Macs is that the overheads are so small: relatively few APIs; fairly shallow OS; fewer libraries. So, it's more problem solving and less gluing.

Onto the next bit. I've frequently read that the Mac 128kB had about 80kB free for applications, but that doesn't mean there's really 80kB of free space for an App at any one point (obvs Segmentation helps). So, I wrote a simple Free memory application to check how much is really there!

C:
/**
 * FreeMem.
 */

#define kNumDigits 5
char gNum[kNumDigits];

void ToolboxInit(void)
{
    InitGraf(&thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(NULL);
    MaxApplZone();
}

void main(void)
{
    WindowPtr win;
    Rect bounds;
    Ptr p=NULL;
    long kb=0;
    ToolboxInit();
    SetRect(&bounds,20,40,100,54);
    win=NewWindow(NULL, &bounds, "\pFreeMem", TRUE,
                noGrowDocProc, (Ptr)-1L, FALSE, 0L);
    ShowWindow(win);
    SetPort(win);
    TextMode(srcCopy);
    do {
        if(p!=NULL) {
            DisposePtr(p);
        }
        ++kb;
        p=NewPtr(kb<<10L);
        NumToString(kb,gNum);
        MoveTo(2,12);
        DrawString(gNum);
    }while(p!=NULL);
    while(!Button()) {
    }
}

It's deliberately ultra-rudimentary at 162b of compiled code so the application overhead would be minimal.

SystemMacFree/KbAppSize/kbOverhead
1.0-2.1128kB75251
1.0-3.2512Ke429281
3.3512Ke4062104
4.1512Ke3912119
5.0-5.1 (not MultiFinder)512Ke3472163

So, for all the 128kB Mac Systems that'll run, there's 75kB free and for most of the 512Ke systems that run it's 429kB going down to 391kB for System 4.1 (which we used a bit).

For the kind of fun applications I'd develop, 75kB will probably be plenty. Given each line of code is about 10b (in fact FreeMem averages 5.4b/line), a 75Kb app is about 7.5k lines of code, and I doubt I'll be bothered to write that much for any of these (though a few thousand is plausible).
 

Attachments

OK, this is a weird one. I've just been doing some more THINK C programming, but now find I'm getting Out of Memory errors on a 4MB Mac Plus under miniVMac trying to run/debug the DTMF app. It seems like there's plenty free though:

1731362995833.png
THINKC is only using half its allocation; there's nearly 2MB free. The app is tiny!

Any ideas? I've tried quitting THINKC and even restarting the emulated Mac.

-cheers from Julz
 
Trying to run it not build it? Does the application's resource file have a SIZE resource?
No, but your comment helped me work out what I'd done wrong. In ThinkC you can set the SIZE resource from the Project:Set Project Type.. menu option. In my original DTMF program, I had tried to see what the minimum partition it could run in as a standalone application was, to which the answer was 16kB in System 6 and 24kB in System 7. However, when I then went back to it to debug it, 16kB isn't big enough.

-cheers from Julz
 
Back
Top