Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions LidAngleSensor/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@
#import "LidAngleSensor.h"
#import "CreakAudioEngine.h"
#import "ThereminAudioEngine.h"
#import "NoiseAudioEngine.h"
#import "NSLabel.h"

typedef NS_ENUM(NSInteger, AudioMode) {
AudioModeCreak,
AudioModeTheremin
AudioModeTheremin,
AudioModeNoise
};

@interface AppDelegate ()
@property (strong, nonatomic) LidAngleSensor *lidSensor;
@property (strong, nonatomic) CreakAudioEngine *creakAudioEngine;
@property (strong, nonatomic) ThereminAudioEngine *thereminAudioEngine;
@property (strong, nonatomic) NoiseAudioEngine *noiseAudioEngine;
@property (strong, nonatomic) NSLabel *angleLabel;
@property (strong, nonatomic) NSLabel *statusLabel;
@property (strong, nonatomic) NSLabel *velocityLabel;
Expand Down Expand Up @@ -120,9 +123,10 @@ - (void)createWindow {

// Create mode selector
self.modeSelector = [[NSSegmentedControl alloc] init];
[self.modeSelector setSegmentCount:2];
[self.modeSelector setSegmentCount:3];
[self.modeSelector setLabel:@"Creak" forSegment:0];
[self.modeSelector setLabel:@"Theremin" forSegment:1];
[self.modeSelector setLabel:@"Noise" forSegment:2];
[self.modeSelector setSelectedSegment:0]; // Default to creak
[self.modeSelector setTarget:self];
[self.modeSelector setAction:@selector(modeChanged:)];
Expand Down Expand Up @@ -188,8 +192,9 @@ - (void)initializeLidSensor {
- (void)initializeAudioEngines {
self.creakAudioEngine = [[CreakAudioEngine alloc] init];
self.thereminAudioEngine = [[ThereminAudioEngine alloc] init];
self.noiseAudioEngine = [[NoiseAudioEngine alloc] init];

if (self.creakAudioEngine && self.thereminAudioEngine) {
if (self.creakAudioEngine && self.thereminAudioEngine && self.noiseAudioEngine) {
[self.audioStatusLabel setStringValue:@""];
} else {
[self.audioStatusLabel setStringValue:@"Audio initialization failed"];
Expand Down Expand Up @@ -247,6 +252,8 @@ - (id)currentAudioEngine {
return self.creakAudioEngine;
case AudioModeTheremin:
return self.thereminAudioEngine;
case AudioModeNoise:
return self.noiseAudioEngine;
default:
return self.creakAudioEngine;
}
Expand Down Expand Up @@ -302,6 +309,7 @@ - (void)updateAngleDisplay {
double volume = [currentEngine currentVolume];
[self.audioStatusLabel setStringValue:[NSString stringWithFormat:@"Freq: %.1f Hz, Vol: %.2f", frequency, volume]];
}
// TODO: noise
}
}

Expand Down
56 changes: 56 additions & 0 deletions LidAngleSensor/NoiseAudioEngine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// NoiseAudioEngine.h
// LidAngleSensor
//
// Created by Sam on 2025-09-06.
//

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

/**
* Synthesized filtered noise
*
* Generate random noise, and filter it with a second order low pass filter, with a high quality
* factor (Q) and a cutoff frequency mapped to the lid angle.
* Biquad coeffs are updated with bilinear transform so that filter remains stable
*
* Most of the code was copied from from ThereminAudioEngine.m
*/
@interface NoiseAudioEngine : NSObject

@property (nonatomic, assign, readonly) BOOL isEngineRunning;
@property (nonatomic, assign, readonly) double currentVelocity;
@property (nonatomic, assign, readonly) double currentFrequency;
@property (nonatomic, assign, readonly) double currentVolume;

/**
* Initialize the audio engine.
* @return Initialized engine instance, or nil if initialization failed
*/
- (instancetype)init;

/**
* Start the audio engine and begin tone generation.
*/
- (void)startEngine;

/**
* Stop the audio engine and halt tone generation.
*/
- (void)stopEngine;

/**
* Update based on new lid angle measurement.
* This method calculates frequency mapping and volume based on movement.
* @param lidAngle Current lid angle in degrees
*/
- (void)updateWithLidAngle:(double)lidAngle;

/**
* Manually set the angular velocity (for testing purposes).
* @param velocity Angular velocity in degrees per second
*/
- (void)setAngularVelocity:(double)velocity;

@end
Loading