OSStatus AUEffectBase::ChangeStreamFormat( AudioUnitScope inScope, AudioUnitElement inElement, const CAStreamBasicDescription & inPrevFormat, const CAStreamBasicDescription & inNewFormat) { OSStatus result = AUBase::ChangeStreamFormat(inScope, inElement, inPrevFormat, inNewFormat); if (result == noErr) { // for the moment this only dependency we know about // where a parameter's range may change is with the sample rate // and effects are only publishing parameters in the global scope! if (GetParamHasSampleRateDependency() && fnotequal(inPrevFormat.mSampleRate, inNewFormat.mSampleRate)) PropertyChanged(kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0); } return result; }
OSStatus AudioOutputVolumeUp(AudioDeviceID device, UInt32 *level) { Float32 right, left; OSStatus err = AudioOutputGetVolume(device, &left, &right); if (noErr == err) { Float32 max = left > right ? left : right; UInt32 lvl = __AudioOutputVolumeGetLevel(max); if (kAudioOutputVolumeMaxLevel == lvl) { /* If not max level */ if (fnotequal(max, 1)) { err = _AudioOutputSetVolume(device, left, right, 1); } } else { lvl++; check(lvl <= kAudioOutputVolumeMaxLevel); err = _AudioOutputSetVolume(device, left, right, kAudioOutputVolumeLevels[lvl]); } if (level) *level = lvl; } return err; }
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { bool theAnswer = false; bool isDone = false; // note that if either side is 0, that field is skipped // format ID is the first order sort if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0))) { if(x.mFormatID != y.mFormatID) { // formats are sorted numerically except that linear // PCM is always first if(x.mFormatID == kAudioFormatLinearPCM) { theAnswer = true; } else if(y.mFormatID == kAudioFormatLinearPCM) { theAnswer = false; } else { theAnswer = x.mFormatID < y.mFormatID; } isDone = true; } } // mixable is always better than non-mixable for linear PCM and should be the second order sort item if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) { if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0)) { theAnswer = true; isDone = true; } else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0)) { theAnswer = false; isDone = true; } } // floating point vs integer for linear PCM only if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM))) { if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat)) { // floating point is better than integer theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat; isDone = true; } } // bit depth if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0))) { if(x.mBitsPerChannel != y.mBitsPerChannel) { // deeper bit depths are higher quality theAnswer = x.mBitsPerChannel < y.mBitsPerChannel; isDone = true; } } // sample rate if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate)) { if(fnotequal(x.mSampleRate, y.mSampleRate)) { // higher sample rates are higher quality theAnswer = x.mSampleRate < y.mSampleRate; isDone = true; } } // number of channels if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0))) { if(x.mChannelsPerFrame != y.mChannelsPerFrame) { // more channels is higher quality theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame; isDone = true; } } return theAnswer; }
// _______________________________________________________________________________________ // // called to create the file -- or update its format/channel layout/properties based on an encoder // setting change void CAAudioFile::FileFormatChanged(const FSRef *parentDir, CFStringRef filename, AudioFileTypeID filetype) { LOG_FUNCTION("CAAudioFile::FileFormatChanged", "%p", this); XThrowIf(mMode != kPreparingToCreate && mMode != kPreparingToWrite, kExtAudioFileError_InvalidOperationOrder, "new file not prepared"); UInt32 propertySize; OSStatus err; AudioStreamBasicDescription saveFileDataFormat = mFileDataFormat; #if VERBOSE_CONVERTER mFileDataFormat.PrintFormat(stdout, "", "Specified file data format"); #endif // Find out the actual format the converter will produce. This is necessary in // case the bitrate has forced a lower sample rate, which needs to be set correctly // in the stream description passed to AudioFileCreate. if (mConverter != NULL) { propertySize = sizeof(AudioStreamBasicDescription); Float64 origSampleRate = mFileDataFormat.mSampleRate; XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCurrentOutputStreamDescription, &propertySize, &mFileDataFormat), "get audio converter's output stream description"); // do the same for the channel layout being output by the converter #if VERBOSE_CONVERTER mFileDataFormat.PrintFormat(stdout, "", "Converter output"); #endif if (fiszero(mFileDataFormat.mSampleRate)) mFileDataFormat.mSampleRate = origSampleRate; err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterOutputChannelLayout, &propertySize, NULL); if (err == noErr && propertySize > 0) { AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize)); err = AudioConverterGetProperty(mConverter, kAudioConverterOutputChannelLayout, &propertySize, layout); if (err) { free(layout); XThrow(err, "couldn't get audio converter's output channel layout"); } mFileChannelLayout = layout; #if VERBOSE_CHANNELMAP printf("got new file's channel layout from converter: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); #endif free(layout); } } // create the output file if (mMode == kPreparingToCreate) { CAStreamBasicDescription newFileDataFormat = mFileDataFormat; if (fiszero(newFileDataFormat.mSampleRate)) newFileDataFormat.mSampleRate = 44100; // just make something up for now #if VERBOSE_CONVERTER newFileDataFormat.PrintFormat(stdout, "", "Applied to new file"); #endif XThrowIfError(AudioFileCreate(parentDir, filename, filetype, &newFileDataFormat, 0, &mFSRef, &mAudioFile), "create audio file"); mMode = kPreparingToWrite; mOwnOpenFile = true; } else if (saveFileDataFormat != mFileDataFormat || fnotequal(saveFileDataFormat.mSampleRate, mFileDataFormat.mSampleRate)) { // second check must be explicit since operator== on ASBD treats SR of zero as "don't care" if (fiszero(mFileDataFormat.mSampleRate)) mFileDataFormat.mSampleRate = mClientDataFormat.mSampleRate; #if VERBOSE_CONVERTER mFileDataFormat.PrintFormat(stdout, "", "Applied to new file"); #endif XThrowIf(fiszero(mFileDataFormat.mSampleRate), kExtAudioFileError_InvalidDataFormat, "file's sample rate is 0"); XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyDataFormat, sizeof(AudioStreamBasicDescription), &mFileDataFormat), "couldn't update file's data format"); } UInt32 deferSizeUpdates = 1; err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyDeferSizeUpdates, sizeof(UInt32), &deferSizeUpdates); if (mConverter != NULL) { // encoder // get the magic cookie, if any, from the converter delete[] mMagicCookie; mMagicCookie = NULL; mMagicCookieSize = 0; err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, NULL); // we can get a noErr result and also a propertySize == 0 // -- if the file format does support magic cookies, but this file doesn't have one. if (err == noErr && propertySize > 0) { mMagicCookie = new Byte[propertySize]; XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, mMagicCookie), "get audio converter's magic cookie"); mMagicCookieSize = propertySize; // the converter lies and tell us the wrong size // now set the magic cookie on the output file UInt32 willEatTheCookie = false; // the converter wants to give us one; will the file take it? err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData, NULL, &willEatTheCookie); if (err == noErr && willEatTheCookie) { #if VERBOSE_CONVERTER printf("Setting cookie on encoded file\n"); #endif XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, mMagicCookieSize, mMagicCookie), "set audio file's magic cookie"); } } // get maximum packet size propertySize = sizeof(UInt32); XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertyMaximumOutputPacketSize, &propertySize, &mFileMaxPacketSize), "get audio converter's maximum output packet size"); AllocateBuffers(true /* okToFail */); } else { InitFileMaxPacketSize(); } if (mFileChannelLayout.IsValid() && mFileChannelLayout.NumberChannels() > 2) { // don't bother tagging mono/stereo files UInt32 isWritable; err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, NULL, &isWritable); if (!err && isWritable) { #if VERBOSE_CHANNELMAP printf("writing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); #endif err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyChannelLayout, mFileChannelLayout.Size(), &mFileChannelLayout.Layout()); if (err) CAXException::Warning("could not set the file's channel layout", err); } else { #if VERBOSE_CHANNELMAP printf("file won't accept a channel layout (write)\n"); #endif } } UpdateClientMaxPacketSize(); // also sets mFrame0Offset mPacketMark = 0; mFrameMark = 0; }