Re: Bug in saving user presets [Solved]
Re: Bug in saving user presets [Solved]
- Subject: Re: Bug in saving user presets [Solved]
- From: Robert Abernathy <email@hidden>
- Date: Fri, 27 Jan 2006 13:00:35 +0000
The problem turns out to be in AUElement. If the Auto-vectorization
flag is set in the compiler, SaveState and RestoreState shift the
order of the preset values. This may not show in AU's with a small
number of presets.
Since the audio portions of the AU are all done using the Accelerate
framework, this flag isn't getting me anything anyway. So, my problem
is solved. But, it is a bit weird and a major pain to track down.
Rob
On 25 Jan 2006, at 21:39, Robert Abernathy wrote:
I'm tracking down a bug in user presets in an AU I'm working on.
I've tracked it down to being in AUBase::SaveState or
AUElement::SaveState.
The parameter data is being gathered correctly in
AUElement::SaveState. If I print it here as it is being pulled
from mParameters or mIndexedParameters, it is correct.
If I take the, the dictionary that is built in AUBase::SaveState
and print it out immediately after the parameter data is added, I
can see that the data is wrong at this point. (See code below, the
function TestState is where the data is checked. It mimics the
read data in AUElement::RestoreState to do the dictionary/data read.)
The parameter data is offset by two indices. As the parameters are
read back in AUElement::PrintState, the zeroth and first elements
are garbage (close to zero). The 2nd entry contains the value of
the zeroth parameter. The 3rd entry contains the value of the
first parameter and so forth, up to the 90th entry containing the
value of the 88th parameter. The 89th and 90th parameters are
missing.
If I print the data out as it is being read back in
AUElement::RestoreState, the pattern above is the same. Shifted
off by two with the first two entries garbage.
The code I used for testing is below.
Any help would be much appreciated as I'm kinda stuck here.
Thanks,
Rob
Code
below-----------------------------------------------------------------
-------------
ComponentResult AUBase::SaveState( CFPropertyListRef * outData)
{
ComponentDescription desc;
OSStatus result = GetComponentInfo((Component)GetComponentInstance
(), &desc, NULL, NULL, NULL);
if (result) return result;
CFMutableDictionaryRef dict = CFDictionaryCreateMutable (NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// first step -> save the version to the data ref
SInt32 value = kCurrentSavedStateVersion;
AddNumToDictionary (dict, kVersionString, value);
// second step -> save the component type, subtype, manu to the
data ref
value = desc.componentType;
AddNumToDictionary (dict, kTypeString, value);
value = desc.componentSubType;
AddNumToDictionary (dict, kSubtypeString, value);
value = desc.componentManufacturer;
AddNumToDictionary (dict, kManufacturerString, value);
// fourth step -> save the state of all parameters on all scopes
and elements
CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
for (AudioUnitScope iscope = 0; iscope < 4; ++iscope) {
if (iscope == kAudioUnitScope_Group)
continue;
AUScope &scope = GetScope(iscope);
AudioUnitElement nElems = scope.GetNumberOfElements();
for (AudioUnitElement ielem = 0; ielem < nElems; ++ielem) {
AUElement *element = scope.GetElement(ielem);
UInt32 nparams = element->GetNumberOfParameters();
if (nparams > 0) {
struct {
UInt32 scope;
UInt32 element;
} hdr;
hdr.scope = EndianU32_NtoB(iscope);
hdr.element = EndianU32_NtoB(ielem);
CFDataAppendBytes(data, (UInt8 *)&hdr, sizeof(hdr));
element->SaveState(data);
}
}
}
// save all this in the data section of the dictionary
CFDictionarySetValue(dict, kDataString, data);
CFRelease (data);
TestState(dict); // my added function to print out the data
//OK - now we're going to do some properties
//save the preset name...
CFDictionarySetValue (dict, kNameString, mCurrentPreset.presetName);
// Does the unit support the RenderQuality property - if so, save
it...
value = 0;
result = DispatchGetProperty (kAudioUnitProperty_RenderQuality,
kAudioUnitScope_Global,
0,
&value);
if (result == noErr) {
AddNumToDictionary (dict, kRenderQualityString, value);
}
// Does the unit support the CPULoad Quality property - if so, save
it...
Float32 cpuLoad;
result = DispatchGetProperty (kAudioUnitProperty_CPULoad,
kAudioUnitScope_Global,
0,
&cpuLoad);
if (result == noErr) {
CFNumberRef num = CFNumberCreate (NULL, kCFNumberFloatType,
&cpuLoad);
CFDictionarySetValue (dict, kCPULoadString, num);
CFRelease (num);
}
// Do we have any element names for any of our scopes?
// first check to see if we have any names...
bool foundName = false;
for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
foundName = GetScope (i).HasElementWithName();
if (foundName)
break;
}
// OK - we found a name away we go...
if (foundName) {
CFMutableDictionaryRef nameDict = CFDictionaryCreateMutable
(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
for (AudioUnitScope i = 0; i < kNumScopes; ++i) {
GetScope (i).AddElementNamesToDict (nameDict);
}
CFDictionarySetValue (dict, kElementNameString, nameDict);
CFRelease (nameDict);
}
// we're done!!!
*outData = dict;
return noErr;
}
// -------------------------------------
// little function to test the data in the preset
void AUBase::TestState(CFMutableDictionaryRef dict) {
std::cout << "AUBase::TestState() . Count " << CFDictionaryGetCount
(dict) << "\n";
CFDataRef data = reinterpret_cast<CFDataRef>(CFDictionaryGetValue
(dict, kDataString));
if (data != NULL)
{
const UInt8 *p, *pend;
p = CFDataGetBytePtr(data);
pend = p + CFDataGetLength(data);
// we have a zero length data, which may just mean there were no
parameters to save!
// if (p >= pend) return noErr;
while (p < pend) {
struct {
UInt32 scope;
UInt32 element;
} hdr;
hdr.scope = EndianU32_BtoN(*(UInt32 *)p); p += sizeof(UInt32);
hdr.element = EndianU32_BtoN(*(UInt32 *)p); p += sizeof(UInt32);
AUScope &scope = GetScope(hdr.scope);
AUElement *element = scope.GetElement(hdr.element);
// $$$ order of operations issue: what if the element does not
yet exist?
// then we just break out of the loop
if (!element)
break;
p = element->PrintState(p);
}
}
}
// My added routine
// It mimicks AUElement::RestoreState
const UInt8 * AUElement::PrintState(const UInt8 *state)
{
const UInt8 *p = state;
UInt32 nparams = EndianU32_BtoN(*(UInt32 *)p);
std::cout << "Print state ... NParams = " << nparams << "\n";
p += sizeof(UInt32);
for (UInt32 i = 0; i < nparams; ++i) {
struct {
UInt32 paramID;
Float32 value;
} entry;
entry.paramID = EndianU32_BtoN(*(UInt32 *)p);
p += sizeof(UInt32);
UInt32 temp = EndianU32_BtoN(*(UInt32 *)p);
entry.value = *(Float32 *)&temp;
p += sizeof(Float32);
std::cout << "Print - Element: id = " << entry.paramID << " value
= " << entry.value << "\n";
}
return p;
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40musicunfolding.com
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden