ftp.nice.ch/pub/next/unix/audio/sndutil.1.3.s.tar.gz#/sndutil-1.3/sndproc/sndproc0.c

This is sndproc0.c in view mode; [Download] [Up]

/* Copyright 1988-1992, NeXT Inc.  All rights reserved. */
/* sndproc0.c - created from fdfilter.c (AP example)
 *
 *	This program reads in a soundfile, applies a black box to
 *	the sound, one frame at a time, and writes a new soundfile.
 *	Currently supports only SND_FORMAT_LINEAR_16.
 *	If the sound is multi-channel, only the first channel is filtered
 *	and the output sound is mono.
 *
 *	Usage:  sndproc0 <inputSoundFile> <outputSoundFile>
 *
 *	The algorithm:
 *          You provide - currently just does a copy
 */
#include <stdio.h>
#include <mach/mach_error.h>
#include <sound/sound.h>

#define	FRAME_SIZE 4096		/* one page of shorts */

static void	processSound(SNDSoundStruct *inputSound,
			    SNDSoundStruct **outputSound);
static void	processFrame(int frameSize,short *inPtr,short *outPtr);
static void	convertToMono(SNDSoundStruct **theSound);
static void	soundErrorExit();
static void	machErrorExit();

/* Static global variables */
static int	soundError;	/* used by soundErrorExit() macro */
static int	machError;	/* used by machErrorExit() macro */
static char	*programName;

void main(int argc, char *argv[])
{
    SNDSoundStruct	*inputSound, 		*outputSound;
    char		*inputSoundFile,	*outputSoundFile;
    long                nsamps;
    short               *ptr;

    /* Check arguments */
    programName = argv[0];
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <inputSoundFile> <outputSoundFile>\n",
	        programName);
	exit(1);
    }
    inputSoundFile  = argv[1];
    outputSoundFile = argv[2];
    	
    /* Read sound file */
    if (soundError = SNDReadSoundfile(inputSoundFile, &inputSound))
	soundErrorExit();
    /* Abort if unsupported format */
    if (inputSound->dataFormat != SND_FORMAT_LINEAR_16) {
        fprintf(stderr, "%s: unsupported sound format: %d\n",
	    programName, inputSound->dataFormat);
	exit(1);
    }

    /* convert to appropriate architecture if neccessary */
    ptr = (short *) ((char *) inputSound + inputSound->dataLocation);
    nsamps = inputSound->dataSize / (sizeof(short) * inputSound->channelCount);
    SNDSwapSoundToHost(ptr, ptr, nsamps, inputSound->channelCount,
		       inputSound->dataFormat);

    /* Convert to mono if required */
    if (inputSound->channelCount > 1) {
        fprintf(stderr, 
		"%s:  Warning: averaging channels "
		"of a %d-channel sound\n", 
		programName,inputSound->channelCount);
	convertToMono(&inputSound);
    }
    
    /* Filter by applying window in the frequency domain */
    processSound(inputSound, &outputSound);
    
    /* convert the sound ready to write out */
    ptr = (short *) ((char *) outputSound + outputSound->dataLocation);
    nsamps = outputSound->dataSize / (sizeof(short)*outputSound->channelCount);
    SNDSwapHostToSound(ptr, ptr, nsamps, outputSound->channelCount,
		       outputSound->dataFormat);

    /* Write sound file */
    if (soundError = SNDWriteSoundfile(outputSoundFile, outputSound))
	soundErrorExit();
}


/*
 * processSound
 *	Apply a "black box" to the input sound
 *	in the frequency domain and write results to the output sound.
 */
static void	processSound(SNDSoundStruct *inputSound,
			    SNDSoundStruct **outputSound)
{
    int		size     = inputSound->dataSize;
    int		format   = inputSound->dataFormat;
    int		rate 	 = inputSound->samplingRate;
    int		channels = inputSound->channelCount;
    short 	*inPtr, *outPtr, *inFramePtr, *outFramePtr, *frameBuffer;
    int		numFrames, frameSize, sizeDone=0;
    
    /* Allocate a new sound (uses vm_allocate() => data is pre-zeroed) */
    if (soundError = SNDAlloc(outputSound, size, format, rate, channels, 4))
	soundErrorExit();
	
    size /= sizeof(short);
    inPtr  = (short *) ((char *) inputSound   + inputSound->dataLocation);
    outPtr = (short *) ((char *) *outputSound + (*outputSound)->dataLocation);

    /* Use vm_allocate() to get page alignment */
    machError = vm_allocate(task_self(),
			    (pointer_t *)&frameBuffer,
			    FRAME_SIZE * sizeof(short),1);
    if (machError != KERN_SUCCESS)
      machErrorExit();

    numFrames = (size + FRAME_SIZE - 1) / FRAME_SIZE;

    /* For each frame, download, filter, upload, and overlap-add into output */
    for (sizeDone=0, inFramePtr=inPtr, outFramePtr=outPtr; 
	 sizeDone < size; 
	 sizeDone+=FRAME_SIZE, inFramePtr+=FRAME_SIZE, outFramePtr+=FRAME_SIZE)
    {
	frameSize = (FRAME_SIZE < (size-sizeDone)? FRAME_SIZE : size-sizeDone);
        processFrame(frameSize,inFramePtr,outFramePtr);
    }

    /* All sound signals should start and end at 0 amp to avoid driver ramp */
    *outPtr = *(outPtr+size-1) = 0;
}

/*
 * processFrame
 */
static void processFrame(int frameSize,short *inPtr,short *outPtr)
{
    int i;
    for (i=0; i<frameSize; i++)
      *outPtr++ = *inPtr++; /* copy */
}

/* Convert multi-channel sound to mono by tossing extra channels */
static void	convertToMono(SNDSoundStruct **theSound)
{
    SNDSoundStruct *newSound;
    short 	*oldPtr, *newPtr;
    int		size     = (*theSound)->dataSize;
    int		format   = (*theSound)->dataFormat;
    int		rate 	 = (*theSound)->samplingRate;
    int		channels = (*theSound)->channelCount;
    int		newSize, i, j, k, s, scl;
    
    newSize = size/channels;
    if (soundError = SNDAlloc(&newSound, newSize, format, rate, 1, 4))
	soundErrorExit();
    oldPtr  = (short *) ((char *) *theSound + (*theSound)->dataLocation);
    newPtr  = (short *) ((char *) newSound + newSound->dataLocation);
#define SCALE_BITS 10
    scl = (1<<SCALE_BITS)/channels;
    for (i = 0, j = 0; i < newSize/sizeof(short); i++, j+=channels) {
	for (k=0, s=0; k<channels; k++)
	  s += (int)oldPtr[j+k];
	s *= scl;
	newPtr[i] = s >> SCALE_BITS;
    }
    if (soundError = SNDFree(*theSound))
	soundErrorExit();
    *theSound = newSound;
}


/* Sound error handling macro */
void soundErrorExit() {
    fprintf(stderr, "%s: sound error: %s\n", programName, 
	    SNDSoundError(soundError));
    exit(1);
}

/* Mach error handling macro */
void machErrorExit() {
    fprintf(stderr, "%s: mach error: %s\n", programName, 
	    mach_error_string(machError)); 
    exit(1); 
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.