Skip to content
Merged
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
52 changes: 48 additions & 4 deletions JammLab.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
import Foundation

struct ScoreDocument: Equatable {
var title: String?
var parts: [ScorePart]

init(title: String? = nil, parts: [ScorePart]) {
self.title = title
self.parts = parts
}
}

struct ScorePart: Equatable, Identifiable {
var id: String
var name: String
var measures: [ScoreMeasure]

init(id: String = "P1", name: String = "Notation", measures: [ScoreMeasure]) {
self.id = id
self.name = name
self.measures = measures
}
}

struct ScoreMeasure: Equatable, Identifiable {
var number: Int
var startTime: TimeInterval
Expand Down
60 changes: 60 additions & 0 deletions JammLab/Services/AudioSampleConverter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import AVFoundation

enum AudioSampleConverter {
static func monoFloatSamples(from buffer: AVAudioPCMBuffer) -> [Float]? {
let frameLength = Int(buffer.frameLength)
let channelCount = Int(buffer.format.channelCount)
guard frameLength > 0, channelCount > 0 else { return [] }
guard buffer.format.commonFormat == .pcmFormatFloat32 else { return nil }

if buffer.format.isInterleaved {
return interleavedMonoFloatSamples(from: buffer, frameLength: frameLength, channelCount: channelCount)
}

return nonInterleavedMonoFloatSamples(from: buffer, frameLength: frameLength, channelCount: channelCount)
}

private static func nonInterleavedMonoFloatSamples(
from buffer: AVAudioPCMBuffer,
frameLength: Int,
channelCount: Int
) -> [Float]? {
guard let channels = buffer.floatChannelData else { return nil }

var mono = Array(repeating: Float(0), count: frameLength)
for channel in 0..<channelCount {
let data = channels[channel]
for index in 0..<frameLength {
mono[index] += data[index] / Float(channelCount)
}
}

return mono
}

private static func interleavedMonoFloatSamples(
from buffer: AVAudioPCMBuffer,
frameLength: Int,
channelCount: Int
) -> [Float]? {
let audioBuffers = UnsafeMutableAudioBufferListPointer(buffer.mutableAudioBufferList)
guard let audioBuffer = audioBuffers.first,
let data = audioBuffer.mData else {
return nil
}

let sampleCount = frameLength * channelCount
let interleaved = data.bindMemory(to: Float.self, capacity: sampleCount)
var mono = Array(repeating: Float(0), count: frameLength)
for frame in 0..<frameLength {
let frameOffset = frame * channelCount
var sum: Float = 0
for channel in 0..<channelCount {
sum += interleaved[frameOffset + channel]
}
mono[frame] = sum / Float(channelCount)
}

return mono
}
}
Loading