A minimal, essential audio looper application for macOS built with SwiftUI and AVFoundation. This application focuses on core looping functionality with a sophisticated unified audio processing system, providing a clean and intuitive interface for recording and playing audio loops.
- Single Loop Recording/Playback: Record audio input into a single loop buffer
- Automatic Playback: Upon stopping recording, immediately begin loop playback
- Unlimited Recording Duration: Record until manually stopped
- Continuous Loop Playback: Loops play continuously until manually stopped
- Record Button (●): Start/stop recording [Return]
- Play Button (▶): Start/stop playback (available when loop exists) [Space]
- Stop Button (■): Stop current recording or playback [Space when recording]
- Pitch Controls: Adjust playback speed ±20%
- Pitch Up (+): Increase speed/pitch by 1% per click [MIDI: F2]
- Pitch Down (-): Decrease speed/pitch by 1% per click [MIDI: G2]
- Reset Pitch (0): Reset to normal speed [MIDI: A2]
- Varispeed Pitch Control: Adjust playback speed ±20% with real-time pitch/speed control
- Input Monitoring Toggle: Control whether input audio is heard through speakers/headphones
- Real-time Level Meter: Visual feedback of incoming audio levels (first channel)
- MIDI Integration: Full MIDI controller support with customizable mappings
- Keyboard Shortcuts: Essential transport controls with tooltips
- Loop Library: Save and load loops with file management
- Native Format Recording: Records in device's native format without conversion
- Multi-Channel Support: Supports any channel configuration (mono, stereo, surround)
- Variable Sample Rate Support: Adapts to any sample rate (44.1kHz, 48kHz, 96kHz, 192kHz, etc.)
- Dynamic Format Detection: Automatically detects and uses device's native audio format
QuickLoops/
├── Models/
│ └── SimpleLoopState.swift # Comprehensive state management
├── Audio/
│ ├── SimpleAudioEngine.swift # Unified tap audio engine
│ ├── SimpleRecorder.swift # Native format recording
│ └── SimplePlayer.swift # Seamless loop playback
├── Views/
│ ├── ContentView.swift # Main application UI
│ ├── TransportControlsView.swift # Four transport buttons
│ └── LevelMeterView.swift # Level meter & monitoring components
├── ViewModels/
│ └── SimpleLooperViewModel.swift # Business logic coordination
└── Utils/
└── AudioUtils.swift # Audio processing utilities
- AVAudioEngine: Core audio processing with unified tap management
- AVAudioInputNode: Multi-channel microphone input with dynamic format detection
- AVAudioMixerNode: Separate monitoring and main mixer nodes
- AVAudioPlayerNode: Loop playback with seamless scheduling
- AVAudioUnitVarispeed: Real-time pitch/speed adjustment (±20%)
- AVAudioFile: Native format file recording and reading
- macOS 13.0 or later
- Xcode 15.0 or later
- Microphone access permission
- Open
QuickLoops.xcodeprojin Xcode - Select the QuickLoops scheme
- Build and run (⌘+R)
- Grant microphone permission when prompted
- Input Monitoring: Use the "Input Monitor" checkbox to control live audio feedback
- Recording: Click the red Record button or press Return to start recording
- Automatic Playback: Recording automatically transitions to playback when stopped
- Manual Playback: Use the green Play button or press Space to start/stop playback
- Stop: Use the yellow Stop button or press Space (when recording) to stop
- Varispeed Control: Adjust playback speed during playback using +/- buttons or MIDI notes
- Save/Load: Use Cmd+S to save loops and Cmd+O to open the loop library
- MIDI Control: Configure MIDI mappings in Settings for hardware controller integration
- Record: Return (Enter) - Start/stop recording
- Play: Space - Start/stop playback (when not recording)
- Stop: Space - Stop recording (when recording is active)
- Clear: Cmd+Delete - Delete current loop
- Save: Cmd+S - Open save dialog for current loop
- Load: Cmd+O - Open loop library
- MIDI Settings: Access via gear icon in toolbar
The application features a clean, minimal design with:
┌─────────────────────────────────────┐
│ Status Display │
│ [Recording/Playing/Stopped] │
├─────────────────────────────────────┤
│ Input Level Meter │
│ ████████░░░░░░░░░░░░ │
├─────────────────────────────────────┤
│ Transport Controls │
│ [●] [▶] [■] │
│ Record Play Stop │
│ │
│ Pitch Controls │
│ [-] [0] [+] │
│ Down Reset Up │
├─────────────────────────────────────┤
│ Input Monitoring │
│ ☐ Input Monitor (OFF by default) │
└─────────────────────────────────────┘
- Large buttons with SF Symbols for clear visual feedback
- Color coding: Record (red), Play (green), Stop (yellow), Pitch (blue/purple)
- Active button states: Color changes and smooth animations when active
- Varispeed display: Shows current pitch adjustment as +/- integer (e.g., +5, -10) on reset button
- Real-time level meter: 20-segment horizontal bars with green/yellow/red zones
- Input monitoring toggle: Speaker icon with clear on/off states
- Responsive UI: Minimal latency with smooth state transitions
- Unified Tap System: Single tap handles both recording and level monitoring
- Native Format Passthrough: Records in device's exact format without conversion
- Dynamic Sample Rate Support: Automatically adapts to any device sample rate
- Multi-Channel Recording: Full support for mono, stereo, and surround configurations
- Throttled Level Updates: 30Hz update rate to prevent performance issues
- Buffer Size: 2048 samples for optimal performance
- Sample Rates: 44.1kHz, 48kHz, 88.2kHz, 96kHz, 176.4kHz, 192kHz, and any device-native rate
- Bit Depths: 16-bit, 24-bit, 32-bit float (device dependent)
- Channels: Mono, stereo, and multi-channel configurations
- Format: Linear PCM in device's native configuration
The application uses a reactive architecture with:
- SimpleLoopState: Observable state object with comprehensive properties
- SimpleLooperViewModel: Coordinates audio components and UI using Combine
- Unified Tap Management: Prevents audio tap conflicts and optimizes performance
- Automatic Detection: Monitors audio device configuration changes
- Format Adaptation: Next recording automatically uses new device format
- Graceful Recovery: Continues current operations when possible
- Detailed Logging: Comprehensive format change information
- Graceful handling of audio engine failures with detailed logging
- Automatic recovery from audio device changes
- Format compatibility validation
- Thread-safe state management
Varispeed allows real-time adjustment of playback speed and pitch during loop playback. This feature uses AVAudioUnitVarispeed to simultaneously change both playback speed and pitch, maintaining musical relationships.
- Range: ±20% playback speed adjustment (0.8x to 1.2x)
- Precision: 1% increments per button press
- Real-time: Changes apply instantly during playback without interruption
- Visual Feedback: Current adjustment displayed as +/- integer (e.g., +5, -10, 0)
- MIDI Support: Full MIDI control via configurable note mappings
- F2 (MIDI note 41): Pitch Up (+1%)
- G2 (MIDI note 43): Pitch Down (-1%)
- A2 (MIDI note 45): Reset Pitch (0%)
- During Playback: Press + button or F2 MIDI note to increase speed/pitch
- Speed Down: Press - button or G2 MIDI note to decrease speed/pitch
- Reset: Press the center button showing current value or A2 MIDI note to reset to normal speed
- Visual Feedback: Current adjustment displayed in real-time on reset button (e.g., "+5", "-10", "0")
- Uses
AVAudioUnitVarispeedin the audio chain between player node and mixer - Rate clamping ensures values stay within ±20% range
- Real-time rate changes without rescheduling playback
- State persists across playback restarts but resets when loop is cleared
The input monitoring toggle allows users to control whether they hear live input audio through speakers/headphones while maintaining full recording capability.
- Monitor Input Checkbox: Located below the input level meter
- Default State: Input monitoring is OFF when the app launches
- Recording Behavior: When monitoring is OFF, recording still captures input audio normally
- Level Display: Input level meter continues to show levels regardless of monitoring state
- Transport Independence: Toggle works in all transport states (stopped, recording, playing)
Uses a dedicated monitoring mixer node in the audio signal path:
inputNode → monitoringMixerNode → mainMixerNode (for monitoring)
inputNode → unifiedTap (for recording & levels - unaffected by monitoring)
When monitoring is disabled, only the monitoring path volume is muted; recording and level monitoring continue normally through the unified tap system.
- Silent Recording: Record without hearing input feedback
- Feedback Prevention: Eliminate input-to-output audio feedback loops
- Focus Recording: Record without audio distractions
- Multi-Channel Recording: Record surround audio while monitoring only stereo
- Input to Monitoring: Near real-time (< 10ms typical)
- Record Start: Immediate buffer capture via unified tap
- Playback Start: File loading + first buffer scheduling (< 100ms)
- Loop Transition: Seamless via pre-scheduled buffers
- CPU Usage: Optimized with throttled updates and unified processing
- Memory Usage: Streaming recording to disk, full file loading for playback
- Multi-Channel Impact: Linear scaling with channel count
- High Sample Rate Support: Automatic adaptation with proportional resource usage
This minimal version intentionally excludes:
- Multiple loop slots
- Overdubbing/layering
- Click track/metronome
- Waveform visualization
- Audio effects (EQ, reverb, etc.)
- File import/export
- BPM detection
- Quantization
- Audio device selection UI
- Loop trimming/editing
- Audio engine starts without errors on various devices
- Input level meter shows real-time levels (first channel for multi-channel)
- Recording captures audio correctly in native format
- Automatic transition from recording to playback
- Loop plays continuously without dropouts
- Transport controls respond correctly in all states
- Varispeed pitch controls work correctly (±20% range)
- Pitch adjustments apply in real-time during playback
- MIDI pitch control notes (F2, G2, A2) function correctly
- Pitch reset returns to normal speed (0%)
- Input monitoring toggle works without affecting recording
- Clear function resets to ready state and varispeed
- No audio dropouts or glitches with format changes
- Memory usage remains stable during extended use
- Multi-channel devices record all channels
- High sample rate devices work correctly
- No audio dropouts during recording/playback
- Responsive UI with minimal latency (< 50ms)
- Stable memory usage during extended use
- Graceful handling of any audio device format
- Smooth operation with multi-channel and high sample rate devices
- Full Multi-Channel Support: Records all input channels without down-mixing
- Variable Sample Rate: Supports any Core Audio compatible sample rate
- Format Preservation: No format conversion during recording
- Device Flexibility: Works with any macOS-compatible audio interface
- Level Monitoring: Only displays levels from first channel (all channels still recorded)
- Playback Compatibility: Playback device must support recorded format (AVFoundation handles conversion)
The app uses dynamic format detection and native format passthrough:
- Queries device format at recording time
- Records in exact device format
- No forced format conversion
- Automatic adaptation to device changes
This project is created as a demonstration of minimal audio looping functionality using SwiftUI and AVFoundation.
This is a minimal implementation focused on core functionality. When contributing:
- Maintain the minimal, single-purpose design philosophy
- Follow SwiftUI and MVVM patterns
- Ensure audio quality and low-latency performance
- Test on multiple audio devices with various formats
- Preserve the clean, uncluttered interface
- Respect the unified tap architecture
Built with SwiftUI and AVFoundation for macOS 13.0+
- macOS 13.0+ (Ventura)
- Built-in microphone or external audio input device
- Audio output device (speakers/headphones)
- Clone the repository
- Open
QuickLoops.xcodeprojin Xcode - Build and run the project (⌘+R)
- Check Input Level: Ensure your audio device is providing input (green bars in level meter)
- Adjust Monitoring: Use the "Input Monitor" checkbox to enable/disable live input monitoring (defaults to OFF)
- Record: Click the Record button (●) to start recording in device's native format
- Stop Recording: Click Record again to stop and automatically prepare for playback
- Play: Click the Play button (▶) to hear your loop
- Adjust Pitch: Use +/- buttons to adjust playback speed/pitch during playback (±20%)
- Reset Pitch: Click the center button (shows current value) to reset to normal speed
- Stop: Click Stop (■) to stop playback
- Clear: Clear function removes the loop and resets pitch to normal
- Input Level Meter: Shows real-time input levels with 20-segment color-coded display
- Monitor Input Toggle: Controls whether you hear live input audio
- ☐ Unchecked (Default): Silent monitoring (input still recorded and levels shown)
- ✓ Checked: Hear input audio through speakers/headphones
- Press Record: Ready to capture new loop in device's native format
- Recording...: Currently capturing audio input via unified tap system
- Playing Loop: Currently playing back recorded audio with seamless looping and varispeed control
- Paused: Audio recorded and ready for playback
- Pitch Up (+): Each press increases speed/pitch by 1% (up to +20%)
- Pitch Down (-): Each press decreases speed/pitch by 1% (down to -20%)
- Reset (0): Returns playback to normal speed (0%)
- Display: Current adjustment shown as +/- integer on reset button
- MIDI: F2 (up), G2 (down), A2 (reset) - configurable in MIDI Settings
- Views: SwiftUI interface components (ContentView, LevelMeterView, TransportControlsView)
- ViewModels: Business logic and state management (SimpleLooperViewModel)
- Models: Data structures and state objects (SimpleLoopState)
- Audio Engine: Unified tap management with monitoring control (SimpleAudioEngine)
Input Device → Input Node → [Unified Tap] → Level Calc + Recording
↓
Monitoring Mixer → Main Mixer → Output Device
- SimpleAudioEngine: Core audio processing with unified tap and monitoring mixer
- SimpleLoopState: Observable state management with monitoring control
- SimpleLooperViewModel: Coordination between UI and audio engine
- LevelMeterView & InputMonitoringToggleView: Separate UI components
- TransportControlsView: State-aware transport buttons
QuickLoops/
├── Audio/
│ ├── SimpleAudioEngine.swift # Unified tap engine with monitoring
│ ├── SimpleRecorder.swift # Native format recording
│ ├── SimplePlayer.swift # Seamless loop playback with varispeed
│ ├── LoopPreviewEngine.swift # Loop library preview engine
│ └── MIDIManager.swift # MIDI controller integration
├── Models/
│ ├── SimpleLoopState.swift # State with monitoring control
│ ├── SavedLoop.swift # Loop file metadata
│ ├── LoopLibrary.swift # Loop collection management
│ └── MIDIConfiguration.swift # MIDI mapping settings
├── ViewModels/
│ ├── SimpleLooperViewModel.swift # Business logic & monitoring actions
│ └── LoopLibraryViewModel.swift # Loop library management
├── Views/
│ ├── ContentView.swift # Main application interface
│ ├── LevelMeterView.swift # Level meter & monitoring components
│ ├── TransportControlsView.swift # Transport buttons with tooltips
│ ├── SaveLoopView.swift # Save loop dialog
│ ├── LoopLibraryView.swift # Loop library browser
│ ├── LoopRowView.swift # Individual loop list item
│ └── MIDISettingsView.swift # MIDI configuration interface
└── Utils/
├── AudioUtils.swift # Audio utility functions
├── LoopFileManager.swift # Loop file management
└── MIDIUtils.swift # MIDI helper functions
This is a focused, minimal application optimized for professional audio workflows. When contributing:
- Maintain the minimal, single-purpose design philosophy
- Follow SwiftUI and MVVM patterns
- Ensure audio quality and low-latency performance
- Test on multiple audio devices with various formats
- Preserve the clean, uncluttered interface
- Respect the unified tap architecture for performance
This project is available under the MIT License.