-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
928 additions
and
0 deletions.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
Pitch Perfect Tuner Watch App/Assets.xcassets/AccentColor.colorset/Contents.json
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"colors" : [ | ||
{ | ||
"idiom" : "universal" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
Pitch Perfect Tuner Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"images" : [ | ||
{ | ||
"filename" : "icon.png", | ||
"idiom" : "universal", | ||
"platform" : "watchos", | ||
"size" : "1024x1024" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
Binary file added
BIN
+68.2 KB
Pitch Perfect Tuner Watch App/Assets.xcassets/AppIcon.appiconset/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// | ||
// Chromatic Tuner.swift | ||
// Pitch Perfect Tuner Watch App | ||
// | ||
// Created by Kyra Cho on 8/25/24. | ||
|
||
import AVFoundation | ||
import Foundation | ||
import SwiftUI | ||
|
||
class PitchDetector: ObservableObject { | ||
private var audioEngine: AVAudioEngine | ||
private var inputNode: AVAudioInputNode | ||
private var audioFormat: AVAudioFormat | ||
|
||
// A buffer to store recent frequency values for averaging | ||
private var frequencyBuffer: [Float] = [] | ||
private let bufferSize = 10 // Adjust this for smoother or more responsive updates | ||
|
||
@Published var detectedPitch: String = "" | ||
|
||
init() { | ||
audioEngine = AVAudioEngine() | ||
inputNode = audioEngine.inputNode | ||
audioFormat = inputNode.outputFormat(forBus: 0) | ||
|
||
startAudioSession() | ||
} | ||
|
||
private func startAudioSession() { | ||
let recordingFormat = inputNode.outputFormat(forBus: 0) | ||
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, time in | ||
self.processAudio(buffer: buffer) | ||
} | ||
|
||
audioEngine.prepare() | ||
|
||
do { | ||
try audioEngine.start() | ||
} catch { | ||
print("Audio Engine couldn't start: \(error.localizedDescription)") | ||
} | ||
} | ||
|
||
private func processAudio(buffer: AVAudioPCMBuffer) { | ||
guard let channelData = buffer.floatChannelData?[0] else { | ||
return | ||
} | ||
|
||
let frameLength = Int(buffer.frameLength) | ||
var zeroCrossings = 0 | ||
var lastValue: Float = channelData[0] | ||
|
||
for i in 1..<frameLength { | ||
let value = channelData[i] | ||
if (value > 0 && lastValue < 0) || (value < 0 && lastValue > 0) { | ||
zeroCrossings += 1 | ||
} | ||
lastValue = value | ||
} | ||
|
||
// Calculate frequency based on zero crossings | ||
let frequency = Float(zeroCrossings) * Float(audioFormat.sampleRate) / Float(frameLength * 2) | ||
|
||
// Add the frequency to the buffer | ||
frequencyBuffer.append(frequency) | ||
|
||
// Keep only the last 'bufferSize' frequencies | ||
if frequencyBuffer.count > bufferSize { | ||
frequencyBuffer.removeFirst() | ||
} | ||
|
||
// Calculate the average frequency | ||
let averageFrequency = frequencyBuffer.reduce(0, +) / Float(frequencyBuffer.count) | ||
|
||
// Update the detected pitch on the main thread with only the averaged frequency | ||
DispatchQueue.main.async { | ||
self.detectedPitch = String(format: "%.2f", averageFrequency) | ||
} | ||
} | ||
|
||
func stop() { | ||
audioEngine.stop() | ||
} | ||
} |
Oops, something went wrong.