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.