Skip to content

Instantly share code, notes, and snippets.

@iskakaushik
Created January 5, 2020 22:40
Show Gist options
  • Save iskakaushik/c39c634d645d95c6bbefdff45d494a1a to your computer and use it in GitHub Desktop.
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.
#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