Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
kyracho authored Aug 26, 2024
1 parent ac14b6b commit 2b0848d
Show file tree
Hide file tree
Showing 13 changed files with 928 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
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
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions Pitch Perfect Tuner Watch App/Assets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
85 changes: 85 additions & 0 deletions Pitch Perfect Tuner Watch App/Chromatic Tuner.swift
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()
}
}
Loading

0 comments on commit 2b0848d

Please sign in to comment.