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
39 changes: 39 additions & 0 deletions App/Sources/Models/MixerState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

/// Per-channel mixer state for the Porta424 six-channel board.
///
/// All continuous values are normalized `0...1`. `pan` follows the hardware
/// convention where `0` is hard-left, `0.5` is center, and `1` is hard-right.
/// EQ knobs are centered at `0.5` (flat); their detent snaps back to flat.
struct ChannelState: Identifiable, Equatable, Sendable {
/// Channel number as printed on the chassis (1...6).
let id: Int

var trim: Double = 0.6
var eqHigh: Double = 0.5
var eqMid: Double = 0.5
var eqLow: Double = 0.5
var fx1Send: Double = 0.0
var fx2Send: Double = 0.0
var pan: Double = 0.5
var level: Double = 0.65 // channel fader
var source: ChannelSource = .line
var isArmed: Bool = false // record-armed to the assigned tape track
}

/// Input source selection for a mixer channel.
enum ChannelSource: String, Equatable, Sendable {
case mic = "MIC"
case line = "LINE"

mutating func toggle() {
self = (self == .mic) ? .line : .mic
}
}

extension Array where Element == ChannelState {
/// The standard six-channel Porta424 board, numbered 1...6.
static var defaultBoard: [ChannelState] {
(1...6).map { ChannelState(id: $0) }
}
}
20 changes: 20 additions & 0 deletions App/Sources/ViewModels/TapeDeckViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ final class TapeDeckViewModel {
var tapePosition: Double = 0 // 0...1
var counterSeconds: Double = 0

/// Six-channel mixer board state. UI-side mixer parameters (trim, EQ, pan,
/// channel faders) that mirror the hardware front panel.
var channels: [ChannelState] = .defaultBoard

var factoryPresets: [PresetItem] = []
var userPresets: [PresetItem] = []
var activePresetId: String?
Expand Down Expand Up @@ -127,6 +131,22 @@ final class TapeDeckViewModel {
tapePosition = 0
}

// MARK: - Mixer Controls

/// Toggle the record-arm state of a mixer channel by its index (0-based).
func toggleArm(channelIndex: Int) {
guard channels.indices.contains(channelIndex) else { return }
channels[channelIndex].isArmed.toggle()
HapticEngine.buttonPress()
}

/// Toggle a channel's input source between MIC and LINE.
func toggleSource(channelIndex: Int) {
guard channels.indices.contains(channelIndex) else { return }
channels[channelIndex].source.toggle()
HapticEngine.buttonPress()
}

// MARK: - Counter String

var counterString: String {
Expand Down
Loading
Loading