Created
January 5, 2020 22:40
-
-
Save iskakaushik/c39c634d645d95c6bbefdff45d494a1a to your computer and use it in GitHub Desktop.
Code to generate basic audio wave forms. Supported waveforms: saw-tooth, sine and square.
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
#include <cmath> | |
#include <cstdlib> | |
#include <string> | |
#import <AudioToolbox/AudioToolbox.h> | |
#import <CoreData/CoreData.h> | |
#import <Foundation/Foundation.h> | |
#define FILENAME_FORMAT @"%0.3f-%@.aif" | |
constexpr int sample_rate = 44100; | |
constexpr float duration_secs = 5.0; | |
enum class WaveType { Saw, Sine, Square, Unknown }; | |
WaveType ParseWaveType(const std::string waveArg) { | |
if (waveArg == "saw") { | |
return WaveType::Saw; | |
} else if (waveArg == "sine") { | |
return WaveType::Sine; | |
} else if (waveArg == "square") { | |
return WaveType::Square; | |
} else { | |
return WaveType::Unknown; | |
} | |
} | |
const auto squareFunc = [](int posInWave, int waveLength) { | |
if (posInWave < waveLength / 2) { | |
return CFSwapInt16HostToBig(SHRT_MAX); | |
} else { | |
return CFSwapInt16HostToBig(SHRT_MIN); | |
} | |
}; | |
const auto sawFunc = [](int posInWave, int waveLength) { | |
const double slope = posInWave / (double)waveLength; | |
return CFSwapInt16HostToBig((slope * SHRT_MAX * 2) - SHRT_MAX); | |
}; | |
const auto sineFunc = [](int posInWave, int waveLength) { | |
const double slope = posInWave / (double)waveLength; | |
const double sineVal = SHRT_MAX * sin(2 * M_PI * slope); | |
return CFSwapInt16HostToBig(sineVal); | |
}; | |
// modifies the sample start to reflect the new sample start. | |
void WriteBytesToAudioFile(const WaveType waveType, AudioFileID audioFile, | |
const int waveLengthInSamples, | |
int64_t &sampleCount) { | |
for (int i = 0; i < waveLengthInSamples; i++, sampleCount++) { | |
SInt16 sample; | |
if (waveType == WaveType::Square) | |
sample = squareFunc(i, waveLengthInSamples); | |
else if (waveType == WaveType::Saw) | |
sample = sawFunc(i, waveLengthInSamples); | |
else if (waveType == WaveType::Sine) | |
sample = sineFunc(i, waveLengthInSamples); | |
UInt32 bytesToWrite = 2; | |
const auto audioErr = AudioFileWriteBytes(audioFile, false, sampleCount * 2, | |
&bytesToWrite, &sample); | |
assert(audioErr == noErr); | |
} | |
} | |
int main(int argc, const char *argv[]) { | |
@autoreleasepool { | |
if (argc != 3) { | |
printf("Expected 2 args. Got: %d\n", argc - 1); | |
return -1; | |
} | |
// first argument is the frequency; | |
const float freq = atof(argv[1]); | |
const std::string waveTypeArg = std::string(argv[2]); | |
const WaveType waveType = ParseWaveType(waveTypeArg); | |
if (waveType == WaveType::Unknown) { | |
printf("Unknown wave type requested."); | |
return -1; | |
} | |
NSString *fileName = [NSString | |
stringWithFormat:FILENAME_FORMAT, freq, | |
[NSString stringWithUTF8String:waveTypeArg.c_str()]]; | |
NSString *filePath = [[NSString stringWithUTF8String:"/tmp/"] | |
stringByAppendingPathComponent:fileName]; | |
NSURL *fileURL = [NSURL fileURLWithPath:filePath]; | |
NSLog(@"Will write to file: %@", fileURL.absoluteString); | |
AudioStreamBasicDescription asbd; | |
memset(&asbd, 0, sizeof(asbd)); | |
asbd.mSampleRate = sample_rate; | |
asbd.mFormatID = kAudioFormatLinearPCM; | |
asbd.mFormatFlags = kAudioFormatFlagIsBigEndian | | |
kAudioFormatFlagIsSignedInteger | | |
kAudioFormatFlagIsPacked; | |
asbd.mBitsPerChannel = 16; | |
asbd.mChannelsPerFrame = 1; | |
asbd.mFramesPerPacket = 1; | |
asbd.mBytesPerFrame = 2; | |
asbd.mBytesPerPacket = 2; | |
AudioFileID audioFile; | |
OSStatus audioErr = noErr; | |
audioErr = | |
AudioFileCreateWithURL((__bridge CFURLRef)fileURL, kAudioFileAIFFType, | |
&asbd, kAudioFileFlags_EraseFile, &audioFile); | |
assert(audioErr == noErr); | |
constexpr int64_t maxSampleCount = sample_rate * duration_secs; | |
const int waveLengthInSamples = sample_rate / freq; | |
for (int64_t sampleCount = 0; sampleCount < maxSampleCount;) { | |
WriteBytesToAudioFile(waveType, audioFile, waveLengthInSamples, | |
sampleCount); | |
} | |
audioErr = AudioFileClose(audioFile); | |
assert(audioErr == noErr); | |
NSLog(@"wrote %lld samples", maxSampleCount); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment