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.