TonnSDK Integration Guide¶
This guide provides step-by-step instructions for integrating TonnSDK into your audio application or Digital Audio Workstation (DAW).
Table of Contents¶
- Prerequisites
- Installation
- CMake Integration
- Manual Integration
- Basic Integration Steps
- GPU Integration (v1.6)
- AudioReprocessor Integration
- Platform-Specific Considerations
- Advanced Integration Patterns
- Troubleshooting
Prerequisites¶
Before integrating TonnSDK, ensure your development environment meets these requirements:
- C++ Compiler: C++17 compatible compiler
- Windows: MSVC 2019+
- macOS: Clang 8+ (Xcode 11+)
- Linux: GCC 7+ or Clang 8+
- Build System: CMake 3.15+ recommended (3.14+ minimum)
- Dependencies:
- Most dependencies are bundled with TonnSDK
- libsndfile (for examples and audio I/O)
- OpenMP (optional, for enhanced performance)
- nlohmann/json (automatically fetched by CMake when needed)
Installation¶
CMake Integration¶
The recommended way to integrate TonnSDK is using CMake:
- Add TonnSDK to your project:
```cmake # In your CMakeLists.txt file
# Option 1: If TonnSDK is installed in a standard location find_package(TonnSDK REQUIRED) target_link_libraries(your_target PRIVATE TonnSDK::tonnsdk)
# Option 2: If TonnSDK is in a custom location set(TonnSDK_DIR "/path/to/TonnSDK/cmake") find_package(TonnSDK REQUIRED) target_link_libraries(your_target PRIVATE TonnSDK::tonnsdk) ```
- Configure include directories:
cmake
target_include_directories(your_target PRIVATE ${TonnSDK_INCLUDE_DIRS})
Manual Integration¶
For build systems other than CMake:
- Include the headers:
Add the TonnSDK include directory to your include path:
cpp
#include "TonnSDK.h"
- Link against the library:
- Windows: Link against
tonnsdk.lib - macOS: Link against
libtonnsdk.dylib - Linux: Link against
libtonnsdk.so
- Deploy runtime libraries:
- Windows: Include
tonnsdk.dllwith your application - macOS: Include
libtonnsdk.dylibwith your application - Linux: Include
libtonnsdk.sowith your application
Basic Integration Steps¶
Follow these steps to integrate TonnSDK into your application:
1. Initialize the SDK¶
#include "TonnSDK.h"
#include "MixTrackSettings.h"
// Initialize with sample rate and musical style
tonn::TonnSDK tonnSDK(44100.0f, tonn::MusicalStyle::POP);
// Or initialize with skip quiet tracks enabled (STABLE in v1.3.1)
// tonn::TonnSDK tonnSDK(44100.0f, tonn::MusicalStyle::POP, true);
// Initialize with license key (required)
if (!tonnSDK.initialize("your-license-key-here")) {
std::cerr << "SDK initialization failed: " << tonnSDK.getLastErrorMessage() << std::endl;
// Handle initialization error
return;
}
// Verify license status (optional)
if (!tonnSDK.isLicenseValid()) {
std::cerr << "License validation failed: " << tonnSDK.getLicenseStatus() << std::endl;
return;
}
2. Configure Track Settings¶
// Create settings for a track using constructor
tonn::MixTrackSettings kickSettings(tonn::GroupType::KICK_GROUP,
tonn::PresenceSetting::NORMAL,
tonn::MusicalStyle::POP);
// Optional: Set additional parameters
kickSettings.setPanPreference(tonn::PanPreference::CENTER); // Center position
kickSettings.setReverbSetting(tonn::ReverbSetting::LOW); // Low reverb
// You can also create default settings and modify them
tonn::MixTrackSettings bassSettings;
bassSettings.setGroupType(tonn::GroupType::BASS_GROUP);
bassSettings.setPresence(tonn::PresenceSetting::NORMAL);
3. Add Audio Tracks¶
// Assuming audioBuffer is a multi-channel buffer of your audio data
// [channel][sample] format, as commonly used in DAWs
std::vector<std::vector<float>> kickBuffer = getAudioBufferFromYourSystem();
// Add the track
tonnSDK.addTrackFromBuffer(kickBuffer, kickSettings);
// Add more tracks as needed...
4. Process the Mix¶
// Process the mix (non-realtime operation)
tonn::MixResult result = tonnSDK.process();
// For faster processing when you only need settings:
// tonn::MixResult settingsResult = tonnSDK.process(true); // settings-only mode
5. Use the Results¶
// Get the final stereo mix
auto finalMix = result.audio_x; // std::pair<std::vector<float>, std::vector<float>>
// Access left and right channels
const std::vector<float>& leftChannel = finalMix.first;
const std::vector<float>& rightChannel = finalMix.second;
// Get processed stems (one for each input track)
auto stems = result.stems; // std::vector<std::pair<std::vector<float>, std::vector<float>>>
// Access individual stems
for (size_t i = 0; i < stems.size(); ++i) {
const std::vector<float>& stemLeft = stems[i].first;
const std::vector<float>& stemRight = stems[i].second;
std::cout << "Stem " << i << ": " << result.trackNames[i] << std::endl;
}
// Get optimized settings for each track
auto optimizedSettings = result.mixTrackSettings;
// Access optimized parameters
for (size_t i = 0; i < optimizedSettings.size(); ++i) {
const auto& settings = optimizedSettings[i];
std::cout << "Track " << i << " - Pan: " << settings.getPanAngle()
<< "°, Gain: " << settings.getGain() << "x" << std::endl;
}
// Get track duration
float durationSeconds = result.trackLengthInSecs;
// Use these results in your application
// For example, write to disk, play through audio engine, etc.
GPU Integration (v1.6)¶
Version 1.6 adds GPU-accelerated mixing for faster processing and higher quality mixes. GPU mode is opt-in — the default CPU_STATIC mode requires no GPU hardware.
Requirements¶
- NVIDIA GPU with CUDA compute capability 6.0+
- CUDA Toolkit 12.2 or later
- NVIDIA Driver compatible with CUDA 12.2+
Enabling GPU Mode¶
tonn::TonnSDK sdk(44100.0f, tonn::MusicalStyle::ROCK_INDIE);
sdk.initialize(licenseKey);
// Enable GPU-accelerated mixing
sdk.setMixingModel(tonn::MixingModel::GPU_STATIC);
// Process as normal — falls back to CPU if GPU is unavailable
tonn::MixResult result = sdk.process();
Docker with GPU¶
To run TonnSDK with GPU support in Docker, ensure the NVIDIA Container Toolkit is installed, then use the --gpus flag:
# Run with GPU support
docker run --gpus all -e TONNSDK_LICENSE_KEY="your_key" tonnsdk:1.6.1
# Or with docker-compose — uncomment the GPU section in docker-compose.yml
docker-compose up --build -d
docker-compose exec tonnsdk /bin/bash
GPU Fallback Behavior¶
If GPU_STATIC is requested but no compatible GPU is available, the SDK automatically falls back to CPU_STATIC processing. No error is thrown — the mix completes using CPU.
Cloud GPU Instances¶
For production deployments, GPU mode works well with cloud GPU instances:
- AWS: g4dn.xlarge or p3.2xlarge instances
- GCP: n1-standard with NVIDIA T4 or V100
- Azure: NC or NV series VMs
Stable Features¶
Skip Quiet Tracks Feature¶
Version 1.3.1 provides stable and enhanced support for gracefully handling quiet or silent audio tracks. This is particularly useful for batch processing workflows where some tracks might be below threshold.
Usage¶
// Enable skip quiet tracks for batch processing
tonn::TonnSDK sdk(44100.0f, tonn::MusicalStyle::ROCK_INDIE, true);
// Initialize with license
if (!sdk.initialize("your-license-key")) {
std::cerr << "Failed to initialize SDK" << std::endl;
return -1;
}
// Add tracks - quiet tracks will be skipped automatically
sdk.addTrack("quiet_track.wav", settings); // Skipped with notification
sdk.addTrack("normal_track.wav", settings); // Processed normally
sdk.addTrack("loud_track.wav", settings); // Processed normally
// Process normally - quiet tracks are already filtered out
tonn::MixResult result = sdk.process();
When Tracks Are Skipped¶
Tracks are considered quiet and skipped when: - RMS level is below 0.0001 (extremely quiet) - ITU loudness measurement is below -70 LUFS - Audio contains only silence or near-silence
When tracks are skipped, you'll see clear notifications like:
Info: Skipping quiet track 'quiet_file.wav' - loudness (-85.2 LUFS) is below silence threshold (-70.0 LUFS)
Batch Processing Example¶
// Process a folder of tracks with skip quiet enabled
tonn::TonnSDK sdk(44100.0f, tonn::MusicalStyle::ROCK_INDIE, true);
sdk.initialize(licenseKey);
std::vector<std::string> trackFiles = getTrackFiles("./audio_folder/");
tonn::MixTrackSettings settings(tonn::GroupType::VOCAL_GROUP,
tonn::PresenceSetting::LEAD,
tonn::MusicalStyle::ROCK_INDIE);
for (const auto& file : trackFiles) {
try {
sdk.addTrack(file, settings); // Quiet tracks automatically skipped
} catch (const std::exception& e) {
std::cerr << "Error adding track " << file << ": " << e.what() << std::endl;
}
}
// Only non-quiet tracks will be processed
tonn::MixResult result = sdk.process();
Pre-gain Preservation Fix¶
Version 1.3.1 provides stable and enhanced pre-gain preservation functionality, where pre-gain values calculated during AddTracks are properly preserved throughout processing.
What's Fixed¶
- Pre-gain values from AddTracks are now accurately preserved
- Final
MixResultcontains correct pre-gain information for each track - Consistent loudness normalization data throughout the processing pipeline
Accessing Pre-gain Values¶
tonn::MixResult result = sdk.process();
for (size_t i = 0; i < result.mixTrackSettings.size(); ++i) {
float preGain = result.mixTrackSettings[i].getPreGain();
std::cout << "Track " << i << " pre-gain: " << preGain
<< " dB (" << std::pow(10.0f, preGain / 20.0f) << "x)" << std::endl;
}
AudioReprocessor Integration¶
The AudioReprocessor feature allows for offline reprocessing of existing stems with modified settings, perfect for iterative mixing workflows and post-processing scenarios.
1. Creating an AudioReprocessor¶
#include "AudioReprocessor.h"
// Option 1: Create from existing TonnSDK instance (recommended)
tonn::TonnSDK tonnSDK(44100.0f, tonn::MusicalStyle::ROCK_INDIE);
std::unique_ptr<tonn::AudioReprocessor> reprocessor = tonnSDK.createReprocessor();
// Option 2: Create independently
tonn::AudioReprocessor reprocessor(44100.0f, tonn::MusicalStyle::ROCK_INDIE);
2. Loading Original Stems¶
// Load stems from original audio files
tonn::MixTrackSettings originalVocalSettings(tonn::GroupType::VOCAL_GROUP,
tonn::PresenceSetting::LEAD,
tonn::MusicalStyle::ROCK_INDIE);
if (!reprocessor->loadStem("original_vocals.wav", originalVocalSettings)) {
std::cerr << "Failed to load vocal stem: " << reprocessor->getLastError() << std::endl;
return;
}
// Load from buffer (useful for DAW integration)
std::vector<std::vector<float>> drumBuffer = getDrumStemFromDAW();
tonn::MixTrackSettings originalDrumSettings(tonn::GroupType::DRUMS_GROUP,
tonn::PresenceSetting::NORMAL,
tonn::MusicalStyle::ROCK_INDIE);
if (!reprocessor->loadStem(drumBuffer, originalDrumSettings, "Drums")) {
std::cerr << "Failed to load drum stem: " << reprocessor->getLastError() << std::endl;
return;
}
3. Modifying Settings and Reprocessing¶
// Create modified settings for reprocessing
std::vector<tonn::MixTrackSettings> modifiedSettings;
// Modify vocal settings - increase compression and EQ
tonn::MixTrackSettings newVocalSettings = originalVocalSettings;
newVocalSettings.setCompressorRatio(6.0f); // More compression
newVocalSettings.setCompressorThreshold(-15.0f); // Lower threshold
newVocalSettings.setEQGains({0, 3, -2, 1, 0, 0}); // EQ boost
modifiedSettings.push_back(newVocalSettings);
// Keep drum settings mostly the same, but adjust pan
tonn::MixTrackSettings newDrumSettings = originalDrumSettings;
newDrumSettings.setPanAngle(-15.0f); // Slight left pan
modifiedSettings.push_back(newDrumSettings);
// Reprocess with new settings
tonn::ReprocessResult result = reprocessor->reprocess(modifiedSettings);
if (!result.success) {
std::cerr << "Reprocessing failed: " << result.errorMessage << std::endl;
return;
}
4. Using Reprocessed Results¶
if (result.hasValidAudio()) {
// Save the new mix
if (!reprocessor->saveReprocessedMix(result, "new_mix_v2.wav")) {
std::cerr << "Failed to save reprocessed mix" << std::endl;
}
// Save individual reprocessed stems
for (size_t i = 0; i < result.getStemCount(); ++i) {
std::string filename = "reprocessed_" + result.trackNames[i] + ".wav";
if (!reprocessor->saveReprocessedStem(result, i, filename)) {
std::cerr << "Failed to save stem: " << filename << std::endl;
}
}
// Access audio data directly for playback or further processing
const auto& leftChannel = result.mixedAudio.first;
const auto& rightChannel = result.mixedAudio.second;
// Send to audio playback system
playAudioInDAW(leftChannel, rightChannel, 44100.0f);
}
5. DAW Integration Pattern¶
Here's a complete pattern for DAW integration:
class DAWTonnSDKIntegration {
private:
tonn::TonnSDK sdk_;
std::unique_ptr<tonn::AudioReprocessor> reprocessor_;
std::vector<tonn::MixTrackSettings> lastUsedSettings_;
public:
DAWTonnSDKIntegration(float sampleRate, tonn::MusicalStyle style)
: sdk_(sampleRate, style) {
if (!sdk_.initialize("your-license-key")) {
throw std::runtime_error("Failed to initialize TonnSDK");
}
reprocessor_ = sdk_.createReprocessor();
}
// Initial mix processing
bool processInitialMix(const std::vector<DAWTrack>& tracks) {
// Add tracks to SDK
for (const auto& track : tracks) {
tonn::MixTrackSettings settings = createSettingsFromDAWTrack(track);
sdk_.addTrackFromBuffer(track.audioBuffer, settings);
}
// Process and store results
tonn::MixResult result = sdk_.process();
// Store settings for potential reprocessing
lastUsedSettings_ = result.mixTrackSettings;
// Save original stems for later reprocessing
sdk_.saveOriginalStems("./stems_backup/", true);
return !result.audio_x.first.empty();
}
// Reprocess with user modifications
bool reprocessWithModifications(const std::vector<ParameterChange>& changes) {
// Load original stems into reprocessor
auto originalPaths = sdk_.getOriginalFilePaths();
for (size_t i = 0; i < originalPaths.size() && i < lastUsedSettings_.size(); ++i) {
if (!reprocessor_->loadStem(originalPaths[i], lastUsedSettings_[i])) {
return false;
}
}
// Apply user modifications to settings
std::vector<tonn::MixTrackSettings> modifiedSettings = lastUsedSettings_;
for (const auto& change : changes) {
applyParameterChange(modifiedSettings[change.trackIndex], change);
}
// Reprocess
tonn::ReprocessResult result = reprocessor_->reprocess(modifiedSettings);
if (result.success) {
// Update DAW with new audio
updateDAWWithNewMix(result.mixedAudio);
return true;
}
return false;
}
private:
void applyParameterChange(tonn::MixTrackSettings& settings, const ParameterChange& change) {
switch (change.parameter) {
case ParameterType::GAIN:
settings.setGain(change.value);
break;
case ParameterType::PAN:
settings.setPanAngle(change.value);
break;
case ParameterType::COMPRESSOR_RATIO:
settings.setCompressorRatio(change.value);
break;
// Handle other parameters...
}
}
};
6. Real-time Preview Pattern¶
For applications requiring real-time parameter adjustments:
class RealtimePreviewSystem {
private:
std::unique_ptr<tonn::AudioReprocessor> reprocessor_;
std::vector<tonn::MixTrackSettings> baselineSettings_;
std::vector<std::string> stemPaths_;
public:
bool setupPreview(const std::vector<std::string>& stemFiles,
const std::vector<tonn::MixTrackSettings>& settings) {
reprocessor_ = std::make_unique<tonn::AudioReprocessor>(44100.0f);
baselineSettings_ = settings;
stemPaths_ = stemFiles;
// Pre-load all stems
for (size_t i = 0; i < stemFiles.size() && i < settings.size(); ++i) {
if (!reprocessor_->loadStem(stemFiles[i], settings[i])) {
return false;
}
}
return true;
}
// Quick preview of parameter changes
std::pair<std::vector<float>, std::vector<float>> previewChanges(
int trackIndex, const ParameterModification& mod) {
// Create modified settings
std::vector<tonn::MixTrackSettings> previewSettings = baselineSettings_;
applyModification(previewSettings[trackIndex], mod);
// Reprocess (this is fast for already-loaded stems)
tonn::ReprocessResult result = reprocessor_->reprocess(previewSettings);
if (result.success && result.hasValidAudio()) {
return result.mixedAudio;
}
// Return empty on failure
return {};
}
};
7. Workflow Integration Best Practices¶
- Cache Original Stems: Use
saveOriginalStems()to save stems for later reprocessing - Batch Parameter Changes: Group multiple parameter changes into a single reprocess call
- Error Handling: Always check
ReprocessResult.successand handle errors gracefully - Resource Management: Clear stems with
clearStems()when switching projects - Performance: AudioReprocessor is optimized for quick iteration on loaded stems
Platform-Specific Considerations¶
macOS¶
On Apple Silicon (arm64) Macs, the SDK provides universal binary support. However, some dependencies like FFTW might require special handling:
# For x86_64 libraries on Apple Silicon
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/usr/local/bin/brew install fftw
In your build configuration:
# For x86_64 target on Apple Silicon
set(CMAKE_OSX_ARCHITECTURES "x86_64")
set(CMAKE_PREFIX_PATH "/usr/local")
Windows¶
Ensure proper Runtime Library settings:
- For Debug:
/MDd(Dynamic Runtime Library) - For Release:
/MD(Dynamic Runtime Library)
Linux¶
Ensure all dependencies are installed:
# Ubuntu/Debian
sudo apt-get install libfftw3-dev libarmadillo-dev libsndfile-dev libomp-dev
Advanced Integration Patterns¶
Settings-Only Processing for Parameter Analysis¶
For applications that need to analyze optimal settings without full audio processing:
// Fast parameter calculation (10-50x faster than full processing)
tonn::MixResult settingsResult = tonnSDK.process(true);
// Analyze the optimized parameters
for (size_t i = 0; i < settingsResult.mixTrackSettings.size(); ++i) {
const auto& settings = settingsResult.mixTrackSettings[i];
// Extract calculated parameters
float panAngle = settings.getPanAngle();
float gain = settings.getGain();
float compThreshold = settings.getCompressorThreshold();
float compRatio = settings.getCompressorRatio();
// Use these parameters in your own processing pipeline
applyCustomProcessing(i, panAngle, gain, compThreshold, compRatio);
}
Group-Based Processing¶
For professional workflows, use the subgroup processing approach:
// Process tracks by instrument group
std::map<tonn::GroupType, std::vector<TrackInfo>> trackGroups;
// Group your tracks by GroupType
// ...
// Process each group separately
std::vector<SubmixResult> submixes;
for (const auto& [groupType, tracks] : trackGroups) {
tonn::TonnSDK groupProcessor(sampleRate, style);
// Initialize the group processor
if (!groupProcessor.initialize(licenseKey)) {
std::cerr << "Failed to initialize group processor" << std::endl;
continue;
}
// Add tracks from this group
for (const auto& track : tracks) {
tonn::MixTrackSettings trackSettings(groupType,
tonn::PresenceSetting::NORMAL,
style);
groupProcessor.addTrackFromBuffer(track.buffer, trackSettings);
}
// Process this group
tonn::MixResult groupResult = groupProcessor.process();
// Store submix
submixes.push_back({groupType, groupResult.audio_x});
}
// Create final mix from submixes
tonn::TonnSDK finalMixProcessor(sampleRate, style);
if (!finalMixProcessor.initialize(licenseKey)) {
std::cerr << "Failed to initialize final mix processor" << std::endl;
return;
}
for (const auto& submix : submixes) {
tonn::MixTrackSettings submixSettings(submix.groupType,
tonn::PresenceSetting::NORMAL,
style);
// Convert stereo pair to multi-channel buffer format
std::vector<std::vector<float>> submixBuffer = {submix.audio.first, submix.audio.second};
finalMixProcessor.addTrackFromBuffer(submixBuffer, submixSettings);
}
// Process final mix
tonn::MixResult finalMixResult = finalMixProcessor.process();
Two-Stage Processing Workflow¶
Combine settings-only processing with full processing for optimal workflows:
// Stage 1: Fast parameter calculation
tonn::MixResult settingsResult = tonnSDK.process(true);
// Allow user to review/modify settings
if (userWantsToModifySettings(settingsResult.mixTrackSettings)) {
// User can adjust the calculated parameters
modifySettingsBasedOnUserInput(settingsResult.mixTrackSettings);
}
// Stage 2: Apply the (possibly modified) settings with full processing
// Note: You would need to create a new SDK instance with the modified settings
// or use the settings to guide your own processing pipeline
tonn::MixResult finalResult = tonnSDK.process(false); // Full processing
Troubleshooting¶
Common Issues¶
-
SDK Initialization Failure: - Ensure the license key is correct and valid - Check that
initialize()is called after the constructor - Verify system date/time is accurate - UsegetLastErrorMessage()for detailed error information -
License Validation Issues: - Use
getLicenseStatus()to get detailed license information - CheckgetRemainingDays()to verify license expiration - EnsuregetLicensee()matches expected customer information -
Build Errors: - Verify all dependencies are correctly installed - Ensure compatible compiler version (C++17 required) - Check build configuration matches (Debug/Release) - Verify include paths point to correct TonnSDK headers
-
Runtime Processing Errors: - Use
getLastErrorMessage()to diagnose processing issues - Verify audio buffers are correctly formatted (multi-channel:[channel][sample]) - Ensure sample rates are consistent across all tracks - Check thatMixTrackSettingsare properly configured -
Performance Issues: - Remember TonnSDK is designed for non-realtime processing - Use
process(true)for settings-only mode when you only need parameters - Process in a background thread to avoid blocking UI - Consider using the group-based approach for large sessions (20+ tracks) -
Memory Issues: - For large sessions, use settings-only mode first to verify feasibility - Process tracks in groups rather than all at once - Ensure proper cleanup of audio buffers after adding to SDK
Debug Information¶
// Example error handling and diagnostics
tonn::TonnSDK sdk(44100.0f, tonn::MusicalStyle::ROCK_INDIE);
if (!sdk.initialize(licenseKey)) {
std::cerr << "Initialization failed: " << sdk.getLastErrorMessage() << std::endl;
std::cerr << "License status: " << sdk.getLicenseStatus() << std::endl;
return 1;
}
std::cout << "Licensed to: " << sdk.getLicensee() << std::endl;
std::cout << "Days remaining: " << sdk.getRemainingDays() << std::endl;
try {
tonn::MixResult result = sdk.process();
if (result.audio_x.first.empty()) {
std::cerr << "Processing failed: " << sdk.getLastErrorMessage() << std::endl;
return 1;
}
std::cout << "Processing successful. Duration: "
<< result.trackLengthInSecs << " seconds" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Exception during processing: " << e.what() << std::endl;
std::cerr << "Last SDK error: " << sdk.getLastErrorMessage() << std::endl;
return 1;
}