This is sndproc_ola.c in view mode; [Download] [Up]
/* Copyright 1988-1992, NeXT Inc. All rights reserved. */ /* sndproc_ola.c - like sndproc0.c but with 50% overlap in frames. * * This program shell is appropriate for a "transform coder" * with 50% overlap, such as used by the Dolby AC-2 system. * * This program reads in a soundfile, applies a black box to * the sound, one frame at a time, and writes a new soundfile. * The frame advances by less than a whole frame on each step, * and the overlapping output frames are added together. * * 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: sndproc_ola <inputSoundFile> <outputSoundFile> * * The algorithm: * You provide - currently just "clears the low-order bit" * of each sample. This is an idempotent operation. That * is, applying this program to its output will produce the * same samples exactly (so you can compare input and output * using cmp). */ /* Here is a test shell script for this program. It needs b.snd to exist. If you detect a bug, make the frame size very small (e.g. 2 or 4) and see if it still happens. */ /* sndproc_ola b.snd b2.snd sndproc_ola b2.snd b3.snd cmp b2.snd b3.snd od -i b3.snd | head | openfile od -i b2.snd | head | openfile */ #include <stdio.h> #include <mach/mach_error.h> #include <sound/sound.h> #include <string.h> /* bcopy */ #include <c.h> /* MAX,MIN */ /* Constants */ #define FRAME_SIZE 4096 /* one page of shorts */ #define FRAME_STEP (FRAME_SIZE >> 1) /* frame step size */ #define OVERLAP_SIZE (FRAME_SIZE-FRAME_STEP) static void processSound(SNDSoundStruct *inputSound, SNDSoundStruct **outputSound); static void processFrame(int frameSize,short *inPtr,short *outPtr); static void addShortArrays(short *dest, short *source, int size); static void copyShortArrays(short *dest, short *source, int size); 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; /* * processFrame */ static void processFrame(int frameSize,short *inPtr,short *outPtr) { int i; static int later = 0; if (later) for (i=0; i<frameSize; i++) *outPtr++ = (*inPtr++ >> 1); /* copy * 1/2 */ else { /* all this is to enable "cmp" to compare input and output */ for (i=0; i<FRAME_STEP; i++) *outPtr++ = *inPtr++ & ~1; /* clear low-order bit */ for (i=0; i<(frameSize - FRAME_STEP); i++) *outPtr++ = (*inPtr++ >> 1); /* copy * 1/2 */ later++; } } /* * main */ 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 host architecture before processing */ 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); /* Write sound file */ ptr = (short *) ((char *) outputSound + outputSound->dataLocation); nsamps = outputSound->dataSize / (sizeof(short)*outputSound->channelCount); SNDSwapHostToSound(ptr, ptr, nsamps, outputSound->channelCount, outputSound->dataFormat); 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 and initial zeros */ machError = vm_allocate(task_self(), (pointer_t *)&frameBuffer, FRAME_SIZE * sizeof(short),1); if (machError != KERN_SUCCESS) machErrorExit(); numFrames = (size + FRAME_STEP - 1) / FRAME_STEP; /* For each frame, download, filter, upload, and overlap-add into output */ for (sizeDone=0, inFramePtr=inPtr, outFramePtr=outPtr; sizeDone < size; sizeDone+=FRAME_STEP, inFramePtr+=FRAME_STEP, outFramePtr+=FRAME_STEP) { frameSize = MIN(FRAME_SIZE,(size-sizeDone)); processFrame(frameSize,inFramePtr,frameBuffer); addShortArrays(outFramePtr, frameBuffer, OVERLAP_SIZE); copyShortArrays(outFramePtr+OVERLAP_SIZE, frameBuffer+OVERLAP_SIZE, FRAME_STEP); } /* All sound signals should start and end at 0 amp to avoid driver ramp */ *outPtr = *(outPtr+size-1) = 0; } /* Add source array to dest array, results in dest */ static void addShortArrays(short *dest, short *source, int size) { int i; for (i = 0; i < size; i++) dest[i] += source[i]; } /* Copy source array to dest array */ static void copyShortArrays(short *dest, short *source, int size) { bcopy((char *)source, (char *)dest, size * sizeof(short)); } /* 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.