Merge pull request #6 from na-2n/feature/stereo

Add stereo recording option
This commit is contained in:
Nick Payne
2025-08-12 12:38:42 +01:00
committed by GitHub
5 changed files with 14 additions and 6 deletions
+2
View File
@@ -7,3 +7,5 @@ DerivedData/
.swiftpm/configuration/registries.json .swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc .netrc
*.pcm
*.wav
+5 -1
View File
@@ -5,6 +5,7 @@ struct AudioTee {
var includeProcesses: [Int32] = [] var includeProcesses: [Int32] = []
var excludeProcesses: [Int32] = [] var excludeProcesses: [Int32] = []
var mute: Bool = false var mute: Bool = false
var stereo: Bool = false
var sampleRate: Double? var sampleRate: Double?
var chunkDuration: Double = 0.2 var chunkDuration: Double = 0.2
@@ -40,6 +41,7 @@ struct AudioTee {
parser.addArrayOption( parser.addArrayOption(
name: "exclude-processes", help: "Process IDs to exclude (space-separated)") name: "exclude-processes", help: "Process IDs to exclude (space-separated)")
parser.addFlag(name: "mute", help: "Mute processes being tapped") parser.addFlag(name: "mute", help: "Mute processes being tapped")
parser.addFlag(name: "stereo", help: "Records in stereo")
parser.addOption( parser.addOption(
name: "sample-rate", name: "sample-rate",
help: "Target sample rate (8000, 16000, 22050, 24000, 32000, 44100, 48000)") help: "Target sample rate (8000, 16000, 22050, 24000, 32000, 44100, 48000)")
@@ -56,6 +58,7 @@ struct AudioTee {
audioTee.includeProcesses = try parser.getArrayValue("include-processes", as: Int32.self) audioTee.includeProcesses = try parser.getArrayValue("include-processes", as: Int32.self)
audioTee.excludeProcesses = try parser.getArrayValue("exclude-processes", as: Int32.self) audioTee.excludeProcesses = try parser.getArrayValue("exclude-processes", as: Int32.self)
audioTee.mute = parser.getFlag("mute") audioTee.mute = parser.getFlag("mute")
audioTee.stereo = parser.getFlag("stereo")
audioTee.sampleRate = try parser.getOptionalValue("sample-rate", as: Double.self) audioTee.sampleRate = try parser.getOptionalValue("sample-rate", as: Double.self)
audioTee.chunkDuration = try parser.getValue("chunk-duration", as: Double.self) audioTee.chunkDuration = try parser.getValue("chunk-duration", as: Double.self)
@@ -107,7 +110,8 @@ struct AudioTee {
let tapConfig = TapConfiguration( let tapConfig = TapConfiguration(
processes: processes, processes: processes,
muteBehavior: mute ? .muted : .unmuted, muteBehavior: mute ? .muted : .unmuted,
isExclusive: isExclusive isExclusive: isExclusive,
isMono: !stereo
) )
let audioTapManager = AudioTapManager() let audioTapManager = AudioTapManager()
+3 -1
View File
@@ -2,10 +2,12 @@ public struct TapConfiguration {
public let processes: [Int32] public let processes: [Int32]
public let muteBehavior: TapMuteBehavior public let muteBehavior: TapMuteBehavior
public let isExclusive: Bool public let isExclusive: Bool
public let isMono: Bool
public init(processes: [Int32], muteBehavior: TapMuteBehavior, isExclusive: Bool) { public init(processes: [Int32], muteBehavior: TapMuteBehavior, isExclusive: Bool, isMono: Bool) {
self.processes = processes self.processes = processes
self.muteBehavior = muteBehavior self.muteBehavior = muteBehavior
self.isExclusive = isExclusive self.isExclusive = isExclusive
self.isMono = isMono
} }
} }
+3 -3
View File
@@ -130,11 +130,11 @@ public class AudioFormatConverter {
targetFormat.mSampleRate = sampleRate targetFormat.mSampleRate = sampleRate
targetFormat.mFormatID = kAudioFormatLinearPCM targetFormat.mFormatID = kAudioFormatLinearPCM
targetFormat.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger targetFormat.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger
targetFormat.mBytesPerPacket = 2
targetFormat.mFramesPerPacket = 1 targetFormat.mFramesPerPacket = 1
targetFormat.mBytesPerFrame = 2
targetFormat.mChannelsPerFrame = 1 // Always mono since tap handles this
targetFormat.mBitsPerChannel = 16 targetFormat.mBitsPerChannel = 16
targetFormat.mChannelsPerFrame = sourceFormat.mChannelsPerFrame
targetFormat.mBytesPerFrame = (targetFormat.mBitsPerChannel / 8) * sourceFormat.mChannelsPerFrame
targetFormat.mBytesPerPacket = targetFormat.mFramesPerPacket * targetFormat.mBytesPerFrame
return try AudioFormatConverter(sourceFormat: sourceFormat, targetFormat: targetFormat) return try AudioFormatConverter(sourceFormat: sourceFormat, targetFormat: targetFormat)
} }
+1 -1
View File
@@ -57,7 +57,7 @@ class AudioTapManager {
description.isPrivate = true description.isPrivate = true
description.muteBehavior = config.muteBehavior.coreAudioValue description.muteBehavior = config.muteBehavior.coreAudioValue
description.isMixdown = true description.isMixdown = true
description.isMono = true description.isMono = config.isMono
description.isExclusive = config.isExclusive description.isExclusive = config.isExclusive
description.deviceUID = nil // system default description.deviceUID = nil // system default
description.stream = 0 // first stream of output device description.stream = 0 // first stream of output device