This project evolved from a simple Python prototype to a polished native macOS application for converting between TP-7 multitrack recordings and individual WAV files. This document captures the development journey, technical decisions, and lessons learned.
Initial Analysis:
- Analyzed TP-7 example file: 12-channel, 24-bit, 48kHz WAV
- Discovered channel layout: 6 stereo pairs (L1,R1,L2,R2,...,L6,R6)
- Built working Python prototype using numpy for proof of concept
Key Files (Historical):
tp7_util.py- Original command-line prototype (no longer used)- Successfully handled 24-bit audio with custom byte manipulation
Hybrid Approach:
- Created SwiftUI interface for better user experience
- Maintained Python backend for audio processing
- Added drag & drop, file dialogs, proper macOS integration
Issues Encountered:
- Python dependency made distribution complex
- User needed to install Python + numpy
- Not a true "native" macOS experience
Migration Challenges:
-
Audio Framework Selection:
- Started with AVFoundation/AVAudioFile
- Hit format compatibility issues with TP-7 files
- Migrated to ExtAudioFile API for better format support
-
Memory Management Crisis:
- Initial approach caused stack buffer overflow
- Large audio files (252 seconds = 12M+ frames) exhausted stack
- Solution: Chunked processing (8192 frames) with heap allocation
-
Audio Format Implementation:
- 24-bit handling in Swift/Core Audio proved complex for export
- Current Solution: Export as 16-bit for broad compatibility
- Import maintains 24-bit: Creates proper TP-7 compatible files
- Stable, reliable implementation for production use
TP-7 Utility.app/
├── SwiftUI Interface (ContentView.swift)
│ ├── Drag & Drop handling
│ ├── Smart auto-detection (export/import)
│ ├── Finder integration
│ └── File save dialogs
├── Audio Engine (AudioProcessor.swift)
│ ├── ExtAudioFile API usage
│ ├── Chunked processing (8192 frames)
│ └── Format conversion logic
└── App Bundle
├── Custom icon (app_icon.png)
├── Info.plist configuration
└── No external dependencies
Export (Multitrack → Individual):
- Open TP-7 file with ExtAudioFile
- Validate channel count (2-12, even numbers only)
- Set client format to float32 for processing
- Read in 8192-frame chunks to avoid stack overflow
- Deinterleave stereo pairs from multitrack stream
- Write individual 16-bit stereo WAV files
Import (Individual → Multitrack):
- Validate input files (max 6, all stereo, same sample rate)
- Determine output channel count (2 × number of files)
- Process in chunks, interleaving stereo pairs
- Write combined multitrack file
Problem: Initial code allocated large arrays on stack
// BAD: Stack allocation for large files
let audioBuffer = [Float](repeating: 0, count: totalSamples) // Stack overflow!Solution: Heap allocation with proper cleanup
// GOOD: Heap allocation with defer cleanup
let audioBuffer = UnsafeMutablePointer<Float>.allocate(capacity: bufferSize)
defer { audioBuffer.deallocate() }AVAudioFile Issues:
- Struggled with TP-7's specific 24-bit format
- "Unsupported audio format" errors
ExtAudioFile Success:
- Better format compatibility
- More control over client/file format separation
- Industry standard for professional audio applications
Chunked Processing Pattern:
let chunkSize: UInt32 = 8192 // Sweet spot for memory vs performance
while totalFramesProcessed < frameCount {
let framesToProcess = min(chunkSize, remaining)
// Process chunk...
totalFramesProcessed += Int64(framesToProcess)
}- Prototype in Python: Fast iteration, great libraries (numpy)
- Hybrid Phase: SwiftUI frontend, Python backend
- Native Implementation: Pure Swift for performance and distribution
./build-app.sh- Compiles Swift code with release optimizations
- Creates proper macOS app bundle structure
- Converts PNG icon to ICNS format (all required sizes)
- Bundles everything into
TP-7 Utility.app
# Development iterations
swift build # Quick compile check
./build-app.sh # Full app bundle
open "TP-7 Utility.app" # Test-
Export Edge Cases:
- 2-channel (1 stereo track) files
- 12-channel (6 stereo tracks) files
- Long recordings (4+ minutes)
- Various sample rates (44.1kHz, 48kHz)
-
Import Scenarios:
- Single file import
- Multiple files (2-6 tracks)
- Mismatched sample rates (proper error handling)
- Non-stereo files (proper validation)
-
Memory Stress Tests:
- Large files that previously caused crashes
- Multiple consecutive operations
- Rapid mode switching
- Export Format: Exports 16-bit files (import maintains 24-bit TP-7 compatibility)
- No Real-time Preview: Cannot preview tracks before conversion
- Fixed Chunk Size: 8192 frames works well but not optimized per system
- Export 24-bit Support: Match export format to TP-7's native 24-bit
- Progress Indicators: Show conversion progress for long files
- Batch Processing: Multiple file operations
- Audio Preview: Waveform display and playback
- Currently unsigned (local development)
- For distribution, would need Apple Developer account
- Code signing and notarization required for Gatekeeper
- macOS 13.0+ (for SwiftUI features used)
- No additional dependencies
- ~1MB app size (very lightweight)
"Failed to write audio file":
- Check output directory permissions
- Verify disk space
- Ensure output format compatibility
"Unsupported audio format":
- File may not be from TP-7 device
- Corrupted file headers
- Unsupported sample rate/bit depth combo
App crashes on large files:
- Verify chunked processing is working
- Check memory allocation patterns
- Monitor heap usage during conversion
# Build and run with debug output
swift build && ./.build/debug/TP7Utility
# Monitor memory usage during app operation
leaks "TP-7 Utility"
# Check audio file properties
afinfo filename.wav
# View app bundle contents
ls -la "TP-7 Utility.app/Contents/"- Proper error handling with Result types
- Memory safety with defer statements
- Resource cleanup (ExtAudioFileDispose)
- Async processing for UI responsiveness
- Chunked processing prevents memory spikes
- Heap allocation for large buffers
- Efficient audio format conversion
- Minimal UI updates during processing
This project demonstrates the evolution from prototype to production, showcasing how initial Python experimentation can inform a native implementation. The key insight was that audio processing requires careful memory management and format compatibility considerations that aren't immediately obvious.
The final Swift implementation provides a superior user experience with smart auto-detection, Finder integration, and reliable TP-7 compatibility. The chunked processing approach and ExtAudioFile usage are the critical technical decisions that made the native implementation viable.
Current Status: Production-ready macOS app with no external dependencies, suitable for distribution to TP-7 users who need seamless multitrack conversion workflows.
Development Context: This CLAUDE.md was created to document the complete development journey, technical decisions, and lessons learned during the creation of TP-7 Utility. It serves as both historical record and future development guide.