summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxant <xant@dyne.org>2012-12-10 17:23:00 (GMT)
committer xant <xant@dyne.org>2012-12-10 17:23:00 (GMT)
commitef95b6b82980475bb59086d0d11b13d5514b90be (patch)
tree23db6065c0d3a43bb7081d12b17b39108036d4a6
parenta893da5838ed8ca8fa27da0e4fa0609c849ab220 (diff)
new entity to generate arbitrary tones
(and binaural beats)
-rw-r--r--JMX.xcodeproj/project.pbxproj14
-rw-r--r--entities/audio/JMXAudioToneGenerator.h20
-rw-r--r--entities/audio/JMXAudioToneGenerator.mm117
3 files changed, 150 insertions, 1 deletions
diff --git a/JMX.xcodeproj/project.pbxproj b/JMX.xcodeproj/project.pbxproj
index 478cc47..299e65d 100644
--- a/JMX.xcodeproj/project.pbxproj
+++ b/JMX.xcodeproj/project.pbxproj
@@ -67,6 +67,8 @@
AA004D8214E7148600009CF9 /* JMXPhidgetEncoderEntity.mm in Sources */ = {isa = PBXBuildFile; fileRef = AA004D8114E7148600009CF9 /* JMXPhidgetEncoderEntity.mm */; };
AA02230F14D8BB8C00E7908F /* JMXScriptPinWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = AA02230E14D8BB8C00E7908F /* JMXScriptPinWrapper.mm */; };
AA08D33B14B5AA4500D19015 /* JMXCodePanel.m in Sources */ = {isa = PBXBuildFile; fileRef = AA08D33A14B5AA4400D19015 /* JMXCodePanel.m */; };
+ AA0A89BD1675E02800FF784F /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA0A89BC1675E02800FF784F /* AudioUnit.framework */; };
+ AA0A89C01675E09C00FF784F /* JMXAudioToneGenerator.mm in Sources */ = {isa = PBXBuildFile; fileRef = AA0A89BF1675E09C00FF784F /* JMXAudioToneGenerator.mm */; };
AA0BFDFE1587E5B600D3C8E4 /* Phidget21.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA0BFDFD1587E5B600D3C8E4 /* Phidget21.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
AA1E53AD14AE114D00F80337 /* JMXGraphFragment.mm in Sources */ = {isa = PBXBuildFile; fileRef = AA1E53AC14AE114D00F80337 /* JMXGraphFragment.mm */; };
AA2BE3F312353BA6006087E7 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA2BE3F212353BA6006087E7 /* CoreAudio.framework */; };
@@ -436,6 +438,9 @@
AA02230E14D8BB8C00E7908F /* JMXScriptPinWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JMXScriptPinWrapper.mm; sourceTree = "<group>"; };
AA08D33914B5AA4400D19015 /* JMXCodePanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMXCodePanel.h; sourceTree = "<group>"; };
AA08D33A14B5AA4400D19015 /* JMXCodePanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JMXCodePanel.m; sourceTree = "<group>"; };
+ AA0A89BC1675E02800FF784F /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
+ AA0A89BE1675E09C00FF784F /* JMXAudioToneGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMXAudioToneGenerator.h; sourceTree = "<group>"; };
+ AA0A89BF1675E09C00FF784F /* JMXAudioToneGenerator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JMXAudioToneGenerator.mm; sourceTree = "<group>"; };
AA0BFDFD1587E5B600D3C8E4 /* Phidget21.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Phidget21.framework; path = /Library/Frameworks/Phidget21.framework; sourceTree = "<absolute>"; };
AA1E53AB14AE114D00F80337 /* JMXGraphFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JMXGraphFragment.h; sourceTree = "<group>"; };
AA1E53AC14AE114D00F80337 /* JMXGraphFragment.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JMXGraphFragment.mm; sourceTree = "<group>"; };
@@ -833,6 +838,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ AA0A89BD1675E02800FF784F /* AudioUnit.framework in Frameworks */,
AA0BFDFE1587E5B600D3C8E4 /* Phidget21.framework in Frameworks */,
AA678A48150CC47D00B2E8F7 /* CoreMedia.framework in Frameworks */,
AA678A46150CBC1000B2E8F7 /* AVFoundation.framework in Frameworks */,
@@ -884,6 +890,7 @@
29B97314FDCFA39411CA2CEA /* MoviePlayerD */ = {
isa = PBXGroup;
children = (
+ AA0A89BC1675E02800FF784F /* AudioUnit.framework */,
AAB50B6514DDA472002F385C /* JMX.entitlements */,
080E96DDFE201D6D7F000001 /* Sources */,
29B97315FDCFA39411CA2CEA /* Other Sources */,
@@ -1390,6 +1397,8 @@
825C30ED1275ADB6006376B8 /* JMXAudioFileEntity.mm */,
825C30F01275ADB6006376B8 /* JMXQtAudioCaptureEntity.h */,
825C30F11275ADB6006376B8 /* JMXQtAudioCaptureEntity.mm */,
+ AA0A89BE1675E09C00FF784F /* JMXAudioToneGenerator.h */,
+ AA0A89BF1675E09C00FF784F /* JMXAudioToneGenerator.mm */,
);
name = Audio;
path = audio;
@@ -1712,7 +1721,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0430;
+ LastUpgradeCheck = 0450;
ORGANIZATIONNAME = Dyne.org;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "JMX" */;
@@ -1989,6 +1998,7 @@
AAEBBA1614FD65CF000DA6F9 /* CIAdditiveBlur.m in Sources */,
AA9B58D914FE1E4F00F63C33 /* NSNumber+V8.mm in Sources */,
AA9B58DA14FE1E4F00F63C33 /* NSString+V8.mm in Sources */,
+ AA0A89C01675E09C00FF784F /* JMXAudioToneGenerator.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2018,6 +2028,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = /Library/Frameworks;
@@ -2069,6 +2080,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = /Library/Frameworks;
diff --git a/entities/audio/JMXAudioToneGenerator.h b/entities/audio/JMXAudioToneGenerator.h
new file mode 100644
index 0000000..e0ff4f0
--- /dev/null
+++ b/entities/audio/JMXAudioToneGenerator.h
@@ -0,0 +1,20 @@
+//
+// JMXAudioFrequency.h
+// JMX
+//
+// Created by xant on 12/10/12.
+// Copyright (c) 2012 Dyne.org. All rights reserved.
+//
+
+#import "JMXEntity.h"
+#import "JMXRunLoop.h"
+
+@interface JMXAudioToneGenerator : JMXEntity
+{
+ JMXOutputPin *audioPin;
+}
+
+@property (atomic, assign) NSNumber *frequency;
+@property (atomic, assign) NSNumber *channelSkew;
+
+@end
diff --git a/entities/audio/JMXAudioToneGenerator.mm b/entities/audio/JMXAudioToneGenerator.mm
new file mode 100644
index 0000000..924f23e
--- /dev/null
+++ b/entities/audio/JMXAudioToneGenerator.mm
@@ -0,0 +1,117 @@
+//
+// JMXAudioFrequency.m
+// JMX
+//
+// Created by xant on 12/10/12.
+// Copyright (c) 2012 Dyne.org. All rights reserved.
+//
+
+#import "JMXAudioToneGenerator.h"
+
+@interface JMXAudioToneGenerator ()
+{
+ double sampleRate;
+ double theta1;
+ double theta2;
+}
+@end
+
+@implementation JMXAudioToneGenerator
+@synthesize frequency, channelSkew;
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ audioPin = [self registerOutputPin:@"audio" withType:kJMXAudioPin];
+ audioPin.mode = kJMXPinModePassive;
+
+ frequency = [[NSNumber numberWithDouble:300] retain];
+ channelSkew = [[NSNumber numberWithDouble:7] retain];
+
+ JMXInputPin *frequencyPin = [self registerInputPin:@"frequency" withType:kJMXNumberPin andSelector:@"setFrequency:" allowedValues:nil initialValue:frequency];
+ [frequencyPin setMinLimit:[NSNumber numberWithFloat:10]];
+ [frequencyPin setMaxLimit:[NSNumber numberWithFloat:500]];
+ JMXInputPin *skewPin = [self registerInputPin:@"channelSkew" withType:kJMXNumberPin andSelector:@"setChannelSkew:" allowedValues:nil initialValue:channelSkew];
+ [skewPin setMinLimit:[NSNumber numberWithFloat:0]];
+ [skewPin setMaxLimit:[NSNumber numberWithFloat:50]];
+ sampleRate = 44100;
+ return self;
+ }
+ return nil;
+}
+
+
+- (void)dealloc
+{
+ [super dealloc];
+ [frequency release];
+ [channelSkew release];
+}
+
+
+- (JMXAudioBuffer *)audio
+{
+ AudioStreamBasicDescription theOutputFormat;
+ Float32 *data;
+ JMXAudioBuffer *audioBuffer = nil;
+
+ // Set the client format to 32bit float data
+ // Maintain the channel count and sample rate of the original source format
+ theOutputFormat.mSampleRate = sampleRate;
+ theOutputFormat.mChannelsPerFrame = 2;
+ theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+ theOutputFormat.mFormatID = kAudioFormatLinearPCM;
+ theOutputFormat.mBytesPerPacket = 4 * theOutputFormat.mChannelsPerFrame;
+ theOutputFormat.mFramesPerPacket = 1;
+ theOutputFormat.mBytesPerFrame = 4 * theOutputFormat.mChannelsPerFrame;
+ theOutputFormat.mBitsPerChannel = 32;
+
+ UInt32 nFrames = 512;
+ UInt32 dataSize = nFrames * theOutputFormat.mBytesPerFrame;
+ data = malloc(dataSize);
+
+ AudioBufferList *theDataBuffer = calloc(1, sizeof(AudioBufferList));
+ theDataBuffer->mNumberBuffers = 1;
+ theDataBuffer->mBuffers[0].mDataByteSize = dataSize;
+ theDataBuffer->mBuffers[0].mNumberChannels = 2;
+ theDataBuffer->mBuffers[0].mData = data;
+
+
+ audioBuffer = [JMXAudioBuffer audioBufferWithCoreAudioBufferList:theDataBuffer
+ andFormat:(AudioStreamBasicDescription *)&theOutputFormat
+ copy:NO
+ freeOnRelease:YES];
+ // Fixed amplitude is good enough for our purposes
+ const double amplitude = 0.25;
+ double freq = [frequency doubleValue];
+ double theta1_increment = 2.0 * M_PI * freq / self->sampleRate;
+ double theta2_increment = 2.0 * M_PI * (freq + [channelSkew doubleValue]) / self->sampleRate;
+
+ // This is a mono tone generator so we only need the first buffer
+ double channel_theta = theta1;
+ double channel2_theta = theta2;
+
+ // Generate the samples
+ for (UInt32 frame = 0; frame < nFrames*2; frame+=2)
+ {
+ data[frame] = sin(channel_theta) * amplitude;
+ data[frame+1] = sin(channel2_theta) * amplitude;
+ channel_theta += theta1_increment;
+ channel2_theta += theta2_increment;
+ if (channel_theta > 2.0 * M_PI)
+ {
+ channel_theta -= 2.0 * M_PI;
+ }
+ if (channel2_theta > 2.0 * M_PI)
+ {
+ channel2_theta -= 2.0 * M_PI;
+ }
+ }
+ theta1 = channel_theta;
+ theta2 = channel2_theta;
+ return audioBuffer;
+
+}
+
+@end