Looking through the ACCodec, ACBaseCodec and ACSimpleCodec classes I noticed that several things looked eerily similar to the old Sound Manager stuff. When I got to the file ACCodecDispatch.h I had an "ah ha" moment.
The template class defined in that file now takes the place of all that screwy C preprocessor bullshit from the old Carbon Sound Manager.
In the old Sound Manager, there would be a file in your project that had contents like:
ComponentSelectorOffset (6)
ComponentRangeCount (2)
ComponentRangeShift (7)
ComponentRangeMask (7F)
ComponentRangeBegin (0)
ComponentError (Target)
ComponentError (Register)
StdComponentCall (Version)
StdComponentCall (CanDo)
StdComponentCall (Close)
StdComponentCall (Open)
ComponentRangeEnd (0)
This tied in to some *really* ugly stuff in the background. To call your FooCodec's Register function it would have to concatenate your codec name ("FooCodec") to a function basename (like "Register") and include the parameters along with any commas to separate those parameters. The whole mess would look like:
#define CALLCOMPONENT_BASENAME() FooCodec
#ifdef CALLCOMPONENT_BASENAME
#ifndef CALLCOMPONENT_GLOBALS
#define CALLCOMPONENT_GLOBALS()
#define ADD_CALLCOMPONENT_COMMA
#else
#define ADD_CALLCOMPONENT_COMMA ,
#endif
#define CALLCOMPONENT_GLUE(a,b) a##b
#define CALLCOMPONENT_STRCAT(a,b) CALLCOMPONENT_GLUE(a,b)
#define ADD_CALLCOMPONENT_BASENAME(name) CALLCOMPONENT_STRCAT(CALLCOMPONENT_BASENAME(),name)
EXTERN_API( ComponentResult ) ADD_CALLCOMPONENT_BASENAME(Open)
(CALLCOMPONENT_GLOBALS() ADD_CALLCOMPONENT_COMMA ComponentInstance self);
#endif /* CALLCOMPONENT_BASENAME */
The system would use it to piece together your FooCodecOpen(FooCodecGlobalsPtr globals, ComponentInstance self) function name.
All of that nonsense is now replaced by (edited for length):
template <class CodecClass>
ComponentResult ACCodecDispatch(ComponentParameters* inParameters, CodecClass* inThis)
{
ComponentResult theError = kAudioCodecNoError;
try
{
switch (inParameters->what)
{
// these selectors don't use the object pointer
case kComponentOpenSelect:
{
CodecClass* theCodec = new CodecClass();
SetComponentInstanceStorage(((AudioCodecOpenGluePB*)inParameters)->inCodec, (Handle)theCodec);
}
break;
};
}
catch(ComponentResult inErrorCode)
{
theError = inErrorCode;
}
catch(...)
{
theError = kAudioCodecUnspecifiedError;
}
return theError;
}
Much cleaner in my view. It uses the power of templates to sub in the correct names and dispatch the component function call to the appropriate class method. Ultimately both things perform the same function, but one way requires you to chase through multiple files to figure out what is going on while the other way just prints the code in a nice, clean manner. I never thought I'd say this, but the C++ way is the "right" way to do this.
Nice job, CoreAudio guys!
9:40:55 PM
|