🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.sources.mac
1 messages
1 total messages Started by Dwight Hare Thu, 31 Mar 1988 04:53
Example use of Mac II sound chip
#33
Author: Dwight Hare
Date: Thu, 31 Mar 1988 04:53
185 lines
6367 bytes
[Example use of Mac II sound chip]

I found programming the Mac II sound chip using the new interface
described in IM Vol. V hard to figure out, so I thought others might
be interested in what appears to be a successful program to play
buffers of sampled sound.  If all of this is obvious to anyone, I'd
like to hear from you!

Dwight
dhare@sun.com

---
/*
 *  play.c - use the mac II sound chip to play a sampled sound in chunks.
 *  The eventual purpose is to do some animation in synch with the music.
 *  Written in MPW C by Dwight Hare, March, 1988.
 */

/* The following defines and data structures are used from sound.h:
 *
 *  #define callBackCmd         13
 *  #define bufferCmd           81
 *  #define initMono            0x80
 *  
 *  typedef struct SndCommand {
 *      unsigned short          cmd;
 *      short                   param1;
 *      long                    param2;
 *  } SndCommand;
 *  
 *  typedef struct SndChannel {
 *      struct SndChannel       *nextChan;
 *      ModifierStubPtr         firstMod;
 *      ProcPtr                 callBack;
 *      long                    userInfo;
 *      Time                    wait;
 *      SndCommand              cmdInProgress;
 *      short                   flags;
 *      short                   qLength;
 *      short                   qHead;
 *      short                   qTail;
 *      SndCommand              queue[stdQLength];
 *  } SndChannel, *SndChannelPtr;
 *  
 *  typedef struct SoundHeader {
 *      char                * samplePtr;
 *      unsigned long       length;
 *      Fixed               sampleRate;
 *      unsigned long       loopStart;
 *      unsigned long       loopEnd;
 *      short               baseNote;
 *      char                sampleArea[0];
 *  } SoundHeader, *SoundHeaderPtr;
 */


#define __ALLNU__       /* needed to get new sound stuff in Sound.h */
#include <memory.h>
#include <sound.h>
#include <toolutils.h>

#define NIL (Ptr)0

/*  
 *  This callback routine is used to indicate when a sound has finished
 *  (I haven't found any other way to do it).
 */
pascal void
snd_done(chan, cmd)
SndChannelPtr chan;
SndCommand *cmd;
{
    chan->userInfo = 1;
}

/*
 *  play plays the given sound in "sample" of length "len" at the sampled
 *  rate "rate" (typically 22255 for a Soundwave sample at the highest
 *  rate) and plays the sound in "incr" chunks (22255 would play in
 *  one second chunks at the rate of 22255).
 */
OSErr
play(sample, len, rate, incr)
unsigned char *sample;
long len, rate, incr;
{
    unsigned char *Sp;
    SndChannelPtr sndp = NIL;
    SndCommand playcmd, callcmd;
    SoundHeaderPtr playbuf, playbuf1, playbuf2;
    long i;
    OSErr err;

    /*
     *  We need two buffers for the bufferCmd since the first one
     *  isn't quite finished when we set up the second one.
     */
    playbuf1 = (SoundHeaderPtr)NewPtr(sizeof(SoundHeader));
    playbuf2 = (SoundHeaderPtr)NewPtr(sizeof(SoundHeader));
    if (playbuf1 == NIL || playbuf2 == NIL) {
        return(-1);
    }
    /*
     *  The loopStart, loopEnd, and baseNote are for playing the
     *  sampled sounds as notes, we are not using that feature.
     */
    playbuf1->sampleRate = FixRatio(rate, 1);
    playbuf2->sampleRate = FixRatio(rate, 1);
    playbuf1->loopStart = 0;
    playbuf2->loopStart = 0;
    playbuf1->loopEnd = 0;
    playbuf2->loopEnd = 0;
    playbuf1->baseNote = 60;
    playbuf2->baseNote = 60;

    /*
     *  Create a new sound channel using the sampled synthesizer played
     *  in mono.  The callback routine will be used below to determine
     *  the end of the sound.
     */
    if ((err = SndNewChannel(&sndp, sampledSynth, initMono, snd_done))
            != noErr) {
        return(err);
    }
    
    /*
     *  The playcmd is used in a SndDoCommand.  The bufferCmd plays the
     *  buffer pointed to by param2 (set below).
     */
    playcmd.cmd = bufferCmd;
    playcmd.param1 = 0;
    
    /*
     *  The callcmd is used in a SndDoCommand.  The callBackCmd calls
     *  the callback routine (snd_done) specified in the SndNewChannel
     *  call.  This callback will be put after each play cmd to indicate
     *  when a sound has (almost) finished.
     */
    callcmd.cmd = callBackCmd;
    callcmd.param1 = 0;
    callcmd.param2 = 0;
    
    /* We start with the first playbuf */
    playbuf = playbuf1;

    for (i = len, Sp = sample; i > 0; i -= incr, Sp += incr) {
            /* change buffers */
        if (playbuf == playbuf1)
            playbuf = playbuf2;
        else playbuf = playbuf1;
            /* set the buffer length to either the increment or
               the rest of the sample */
        playbuf->length = i < incr? i : incr;
            /* Set the pointer to the sound to be played */
        playbuf->samplePtr = Sp;
        /*
         *  Set the bufferCmd pointer to this buffer.  This command
         *  buffer is copied by the SndDoCommand so we don't need
         *  two of them
         */
        playcmd.param2 = (long)playbuf;
            /* set the flag we use in snd_done to indicate the finish */
        sndp->userInfo = 0;
            /* Play the buffer */
        if ((err = SndDoCommand(sndp, &playcmd, true)) != noErr) {
            return(err);
        }
            /* Put the callback in the queue after the sound */
        if ((err = SndDoCommand(sndp, &callcmd, true)) != noErr) {
            return(err);
        }
            /* Now wait for the sound to finish (later we'll do some
               animation) */
        while(sndp->userInfo != 1);
    }
    /*
     *  Cleanup
     */
    if ((err = SndDisposeChannel(sndp, false)) != noErr) {
            return(err);
    }
    DisposPtr(playbuf1); DisposPtr(playbuf2);
    return(noErr);
}
---
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads