Last active
November 18, 2020 15:58
-
-
Save justinlevi/7a846070ee6e7e245cc3 to your computer and use it in GitHub Desktop.
Swift CAToneFileGenerator "Learning Core Audio" Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: Playground - noun: a place where people can play | |
import UIKit | |
import Foundation | |
import AudioToolbox | |
import AVFoundation | |
import XCPlayground | |
func CheckError(error:OSStatus) { | |
if error == 0 {return} | |
switch(error) { | |
// AudioToolbox | |
case kAUGraphErr_NodeNotFound: | |
print("Error:kAUGraphErr_NodeNotFound \n"); | |
case kAUGraphErr_OutputNodeErr: | |
print( "Error:kAUGraphErr_OutputNodeErr \n"); | |
case kAUGraphErr_InvalidConnection: | |
print("Error:kAUGraphErr_InvalidConnection \n"); | |
case kAUGraphErr_CannotDoInCurrentContext: | |
print( "Error:kAUGraphErr_CannotDoInCurrentContext \n"); | |
case kAUGraphErr_InvalidAudioUnit: | |
print( "Error:kAUGraphErr_InvalidAudioUnit \n"); | |
case kAudioToolboxErr_InvalidSequenceType : | |
print( " kAudioToolboxErr_InvalidSequenceType "); | |
case kAudioToolboxErr_TrackIndexError : | |
print( " kAudioToolboxErr_TrackIndexError "); | |
case kAudioToolboxErr_TrackNotFound : | |
print( " kAudioToolboxErr_TrackNotFound "); | |
case kAudioToolboxErr_EndOfTrack : | |
print( " kAudioToolboxErr_EndOfTrack "); | |
case kAudioToolboxErr_StartOfTrack : | |
print( " kAudioToolboxErr_StartOfTrack "); | |
case kAudioToolboxErr_IllegalTrackDestination : | |
print( " kAudioToolboxErr_IllegalTrackDestination"); | |
case kAudioToolboxErr_NoSequence : | |
print( " kAudioToolboxErr_NoSequence "); | |
case kAudioToolboxErr_InvalidEventType : | |
print( " kAudioToolboxErr_InvalidEventType"); | |
case kAudioToolboxErr_InvalidPlayerState : | |
print( " kAudioToolboxErr_InvalidPlayerState"); | |
case kAudioUnitErr_InvalidProperty : | |
print( " kAudioUnitErr_InvalidProperty"); | |
case kAudioUnitErr_InvalidParameter : | |
print( " kAudioUnitErr_InvalidParameter"); | |
case kAudioUnitErr_InvalidElement : | |
print( " kAudioUnitErr_InvalidElement"); | |
case kAudioUnitErr_NoConnection : | |
print( " kAudioUnitErr_NoConnection"); | |
case kAudioUnitErr_FailedInitialization : | |
print( " kAudioUnitErr_FailedInitialization"); | |
case kAudioUnitErr_TooManyFramesToProcess : | |
print( " kAudioUnitErr_TooManyFramesToProcess"); | |
case kAudioUnitErr_InvalidFile : | |
print( " kAudioUnitErr_InvalidFile"); | |
case kAudioUnitErr_FormatNotSupported : | |
print( " kAudioUnitErr_FormatNotSupported"); | |
case kAudioUnitErr_Uninitialized : | |
print( " kAudioUnitErr_Uninitialized"); | |
case kAudioUnitErr_InvalidScope : | |
print( " kAudioUnitErr_InvalidScope"); | |
case kAudioUnitErr_PropertyNotWritable : | |
print( " kAudioUnitErr_PropertyNotWritable"); | |
case kAudioUnitErr_InvalidPropertyValue : | |
print( " kAudioUnitErr_InvalidPropertyValue"); | |
case kAudioUnitErr_PropertyNotInUse : | |
print( " kAudioUnitErr_PropertyNotInUse"); | |
case kAudioUnitErr_Initialized : | |
print( " kAudioUnitErr_Initialized"); | |
case kAudioUnitErr_InvalidOfflineRender : | |
print( " kAudioUnitErr_InvalidOfflineRender"); | |
case kAudioUnitErr_Unauthorized : | |
print( " kAudioUnitErr_Unauthorized"); | |
default: | |
print("huh?") | |
} | |
} | |
let SAMPLE_RATE:Float64 = 44100 | |
let DURATION = 0.001 | |
let TONE:Double = 440 // Hz | |
let FILE_NAME = "\(TONE)-square.aif" | |
//let path = NSBundle.mainBundle().pathForResource(FILE_NAME, ofType: "aif")! | |
//let audioURL = NSURL(fileURLWithPath: path) | |
let fileManager = NSFileManager.defaultManager() | |
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) | |
if let documentDirectory: NSURL = urls.first { | |
let fileURL = documentDirectory.URLByAppendingPathComponent(FILE_NAME) | |
fileURL | |
// Prepare the format | |
var audioFormat = AudioStreamBasicDescription() | |
audioFormat.mSampleRate = SAMPLE_RATE; | |
audioFormat.mFormatID = UInt32(kAudioFormatLinearPCM) | |
audioFormat.mFormatFlags = UInt32(kLinearPCMFormatFlagIsBigEndian) | UInt32(kLinearPCMFormatFlagIsSignedInteger) | UInt32(kLinearPCMFormatFlagIsPacked) | |
audioFormat.mBitsPerChannel = UInt32(16) | |
audioFormat.mChannelsPerFrame = 1 // Mono | |
audioFormat.mBytesPerFrame = UInt32(audioFormat.mChannelsPerFrame * 2) | |
print(audioFormat.mBytesPerFrame) | |
audioFormat.mFramesPerPacket = 1 | |
audioFormat.mBytesPerPacket = audioFormat.mFramesPerPacket * audioFormat.mBytesPerFrame | |
print(audioFormat.mBytesPerPacket) | |
var audioFile:AudioFileID = nil | |
var theErr = OSStatus(noErr) | |
/*! | |
@function AudioFileCreateWithURL | |
@abstract creates a new audio file (or initialises an existing file) | |
@discussion creates a new (or initialises an existing) audio file specified by the URL. | |
Upon success, an AudioFileID is returned which can be used for subsequent calls | |
to the AudioFile APIs. | |
@param inFileRef an CFURLRef fully specifying the path of the file to create/initialise | |
@param inFileType an AudioFileTypeID indicating the type of audio file to create. | |
@param inFormat an AudioStreamBasicDescription describing the data format that will be | |
added to the audio file. | |
@param inFlags relevant flags for creating/opening the file. | |
if kAudioFileFlags_EraseFile is set, it will erase an existing file | |
if not set, then the Create call will fail if the URL is an existing file | |
@param outAudioFile if successful, an AudioFileID that can be used for subsequent AudioFile calls. | |
@result returns noErr if successful. | |
*/ | |
// extern OSStatus | |
// AudioFileCreateWithURL (CFURLRef inFileRef, | |
// AudioFileTypeID inFileType, | |
// const AudioStreamBasicDescription *inFormat, | |
// UInt32 inFlags, | |
// AudioFileID *outAudioFile) __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0); | |
theErr = AudioFileCreateWithURL(fileURL, UInt32(kAudioFileAIFFType), &audioFormat, .EraseFile, &audioFile) | |
let maxSampleCount:CLong = CLong(SAMPLE_RATE * DURATION) | |
var sampleCount = 0 | |
var bytesToWrite:UInt32 = 2 | |
let wavelengthInSamples = SAMPLE_RATE / TONE | |
SHRT_MAX | |
Int16.max | |
while sampleCount < maxSampleCount { | |
for i in 0..<Int(wavelengthInSamples){ | |
// Square Wave | |
//var sample:Int16 = i < Int(wavelengthInSamples) / 2 ? Int16.max : Int16.min //12 & 13 | |
// Saw Wave | |
var sample = Int16(((Double(i) / wavelengthInSamples) * Double(Int16.max) * 2) - Double(Int16.max)) | |
// Sin Wave | |
//var sample = Int16(Double(Int16.max) * sin(2 * M_PI * (Double(i) / wavelengthInSamples))) | |
sample | |
//theErr = AudioFileWriteBytes(audioFile, 0, Int64(sampleCount * 2), &bytesToWrite, &sample) | |
sampleCount++ | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment