A Walk-Through
What We're Making
We'll create Zero.rmod, a simple module that sets every value in the selection of a sound to zero. It will work on 8-bit, 16-bit, float-valued, and double-valued sounds.
Create a Project
Start creating the folder Zero wherever convenient. This will be the project folder for Zero. Next, launch ProjectBuilder.app and choose Project:New... Locate your Zero folder. Change the Project Type to Bundle, and save the project in the Zero folder.
Adding Resound Resources
In the directory, copy the five files that come with the Resound API distribution: Module.h, ModuleMenuNode.h, ModuleSound.h, ModuleSoundView.h and ModuleProtocol.h.
Add Some Code
Launch Edit.app, and create a new file. In this file, add the following:
#import "Module.h"
@interface ZeroModule:Module
{
}
- init;
- zeroSound:sender;
@end
Save this as ZeroModule.h in your Zero folder. Create another file with the following:
#import "ZeroModule.h"
#import
Before we go on, this requires some explaining. Module is the class from which all modules subclass. It contains the machinery necessary to load your module into Resound. ModuleMenuNode is a special class with which you specify the submenu to build in Resound's Modules menu. This node is a tree-node, and every menu entry and submenu you add is added as a leaf in the tree.
The root of this tree is rootModuleMenuNode, which you've inherited from Module. This node represents the Modules menu itself. If you want, say, three items in the Modules menu, add three ModuleMenuNodes as submenus to rootModuleMenuNode. As it is, we're only doing one node: zeroNode.
zeroNode is a leaf node in the tree, so we initialize it as such, declaring its name, its receiver (this instance of ZeroModule), and the message sent when choosing the menu item (zeroSound:).
Now add to this file:
- zeroSound:sender
{
Sound* current= [moduleController currentSound];
SoundView* cview= [moduleController currentSoundView];
int dataFormat= [current dataFormat];
int channelCount= [current channelCount];
int sampleCount= [current sampleCount];
char* data;
int x;
int firstSample,sampleLength;
[cview getSelection: &firstSample size: &sampleLength];
if (current==nil||!sampleLength) // no sound
{
NSRunAlertPanel(@"No Sound",
@"There is no sound with which to perform this operation." ,
@"Okay",nil,nil);
return nil;
}
moduleController, which we've inherited from Module, provides us access to Resound's facilities. Above we've grabbed the current sound and soundview as displayed by Resound, and have begun querying the sound and soundview. If there isn't a selection or the sound is nil, we pop up a message telling the user that there's no sound, and exit.
Note that getSelection: does not always return proper values in NeXT's sound view (a bug). Resound's customized sound view does not fix this entirely, but does at least guarantee that the selection will be between 0 and the maximum number of samples in the sound (NeXT's is often way out of range). Continuing:
[moduleController stop];
[current compactSamples];
[[moduleController currentSoundView] checkForCurrentDataOnPasteboard];
data=(char*) [current data];
SNDSwapSoundToHost
((void*)data, (void*)data, sampleCount, channelCount, dataFormat);
// samples can be stereo or mono. We need to deal with this fact.
firstSample*=channelCount;
sampleLength*=channelCount;
We stop any sound currently playing (just in case), let Resound make sure that the sound we're modifying doesn't have pasteboard information (and deal with it appropriately), compact the samples in the sound so we have a clean array on which to operate, and swap the data in the sound to the format that our type of computer can read (Intel machines' data is backwards from most other machines). Note that we set the data pointer only after compactSamples has been performed, since compactSamples changes the pointer. lastly, we set the first sample and the sample length to take into consideration the fact that the channel count could be either 1 (mono) or 2 (stereo). Onward:
// samples can have many different data formats. We also need to deal
// with this fact!
switch(dataFormat)
{
case SND_FORMAT_MULAW_8:
{
unsigned char mulawzero=SNDMulaw(0); // it's probably 127
char* d=(char*) data;
for (x=firstSample;x
This code zeroes out the array, but it changes the particulars of the array type, depending on the sound format (for SND_FORMAT_LINEAR_16, for example, it treats the array as an array of signed shorts). Any other unusual formats cause it to pop up an alert that says it can't perform the operation. Note that SND_FORMAT_MULAW_8 requires the SNDMuLaw() and SNDIMuLaw() functions.&nbsdp; Continuing:
SNDSwapHostToSound ((void*)data, (void*)data, sampleCount, channelCount, dataFormat); [moduleController soundChanged]; return self; } @end
We finish by swapping the sound back to its "proper" format, and finally informing Resound that we've made modifications to the sound itself.
Compiling the Code
Return to ProjectBuilder.app. Add ZeroModule.m as a class in your Zero project if it's not been included yet. Finally, add the five files files Module.h, ModuleMenuNode.h, ModuleSound.h, ModuleSoundView.h and ModuleProtocol.h as headers in the project by double-clicking "Headers". Then build the project.
A bundle called Zero.bundle should appear in the Zero project directory. Move this bundle into the directory /Local/Library/Resound or into the the Resound subdirectory of your home library directory (~/Library/Resound) so Resound will find it. Rename the bundle Zero.rmod. "rmod" is the standard Resound module extension.
Try It Out
Launch Resound.app. Record a sound and convert it to 16-bit linear. Select a section of the sound. Choose Modules:Zero and have fun!
Cleaning Up
Before you distribute your object to others, you should strip it of extraneous symbols (which should make the bundle considerably smaller). To do this, open the file Makefile.postamble in your Zero project directory.
Change the line
#STRIP_FLAGS = -S
To
STRIP_FLAGS = -x -u
This will strip proper extraneous symbols from the bundle.