mirror of
https://github.com/vale981/openAV-Luppp
synced 2025-03-05 09:01:39 -05:00
662 lines
18 KiB
C++
662 lines
18 KiB
C++
/*
|
|
* Author: Harry van Haaren 2013
|
|
* harryhaaren@gmail.com
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "diskreader.hxx"
|
|
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <stdlib.h>
|
|
#include <libgen.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "config.hxx"
|
|
#include "gui.hxx"
|
|
#include "event.hxx"
|
|
#include "audiobuffer.hxx"
|
|
#include "eventhandler.hxx"
|
|
#include "gmastertrack.hxx"
|
|
|
|
#include "controller/genericmidi.hxx"
|
|
|
|
#include <sndfile.hh>
|
|
#include <samplerate.h>
|
|
|
|
extern Gui* gui;
|
|
|
|
using namespace std;
|
|
|
|
DiskReader::DiskReader()
|
|
{
|
|
resampleQuality = 1;
|
|
|
|
// FIXME: could use a config item of sample location?
|
|
lastLoadedSamplePath = getenv("HOME");
|
|
}
|
|
|
|
int DiskReader::loadPreferences()
|
|
{
|
|
stringstream s;
|
|
s << getenv("HOME") << "/.config/openAV/luppp/luppp.prfs";
|
|
std::ifstream sampleFile( s.str().c_str(), std::ios_base::in|std::ios_base::ate);
|
|
|
|
long file_length = sampleFile.tellg();
|
|
if ( file_length > 0 ) {
|
|
sampleFile.seekg(0, std::ios_base::beg);
|
|
sampleFile.clear();
|
|
char *sampleString = new char[file_length];
|
|
sampleFile.read(sampleString, file_length);
|
|
|
|
cJSON* preferencesJson = cJSON_Parse( sampleString );
|
|
if (!preferencesJson) {
|
|
LUPPP_WARN("Preferences JSON not valid");
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
|
|
|
|
cJSON* resample = cJSON_GetObjectItem( preferencesJson, "resampleQuality" );
|
|
if ( resample ) {
|
|
resampleQuality = resample->valueint;
|
|
if ( resampleQuality == 0 ) {
|
|
LUPPP_NOTE("Using Linear resampling, may reduce quality. Check .config/openAV/luppp/luppp.prfs");
|
|
}
|
|
}
|
|
cJSON* ctlrs = cJSON_GetObjectItem( preferencesJson, "defaultControllers" );
|
|
if ( ctlrs ) {
|
|
//cout << ".ctlr HAS items." << endl;
|
|
int nCtlrs = cJSON_GetArraySize( ctlrs );
|
|
for(int i = 0; i < nCtlrs; i++ ) {
|
|
cJSON* ctlr = cJSON_GetArrayItem( ctlrs, i );
|
|
if( ctlr ) {
|
|
LUPPP_NOTE("Loading controller %s", ctlr->valuestring);
|
|
stringstream s;
|
|
s << getenv("HOME") << "/.config/openAV/luppp/controllers/" << ctlr->valuestring;
|
|
gui->addMidiControllerToSetup( s.str() );
|
|
}
|
|
}
|
|
} else {
|
|
LUPPP_NOTE("No default controllers active.");
|
|
}
|
|
|
|
|
|
cJSON* projDir=cJSON_GetObjectItem(preferencesJson,"saveDirectory");
|
|
string dir=getenv("HOME");
|
|
if(projDir) {
|
|
stringstream s;
|
|
s<<dir<<"/"<<projDir->valuestring;
|
|
dir=s.str();
|
|
}
|
|
gui->setProjectsDir(dir);
|
|
|
|
//Enable per track send and resturn jack ports?
|
|
cJSON* jackPerTrackOutput=cJSON_GetObjectItem(preferencesJson,"enablePerTrackOutput");
|
|
if(jackPerTrackOutput) {
|
|
gui->enablePerTrackOutput=jackPerTrackOutput->valueint;
|
|
if(gui->enablePerTrackOutput)
|
|
LUPPP_NOTE("Enabling per track output ports");
|
|
}
|
|
|
|
//Metronome on by default?
|
|
cJSON* metronomeActive=cJSON_GetObjectItem(preferencesJson,"metronomeActiveByDefault");
|
|
if(metronomeActive) {
|
|
EventMetronomeActive e = EventMetronomeActive( metronomeActive->valueint);
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
|
|
//Metronome default volume
|
|
cJSON* metronomeVol=cJSON_GetObjectItem(preferencesJson,"metronomeDefaultVolume");
|
|
if(metronomeVol) {
|
|
float vol=metronomeVol->valueint/100.0f;
|
|
EventMetronomeVolume e(vol);
|
|
writeToDspRingbuffer(&e);
|
|
}
|
|
|
|
|
|
cJSON_Delete( preferencesJson );
|
|
delete[] sampleString;
|
|
} else {
|
|
// empty file / file no exists:
|
|
LUPPP_WARN("Preferences, file doesn't exist: ~/.config/openAV/luppp/luppp.prefs");
|
|
|
|
// so write default file
|
|
gui->getDiskWriter()->writeDefaultConfigToUserHome();
|
|
|
|
return LUPPP_RETURN_OK;
|
|
}
|
|
|
|
return LUPPP_RETURN_OK;
|
|
}
|
|
|
|
int DiskReader::showAudioEditor(AudioBuffer* ab)
|
|
{
|
|
while ( ab->getBeats() == 0 ) {
|
|
// FIXME: Cancel = no load sample?
|
|
gui->getAudioEditor()->show( ab, true );
|
|
|
|
while ( gui->getAudioEditor()->shown() ) Fl::wait();
|
|
|
|
// handle "cancel" return
|
|
if ( ab->getBeats() == -1 ) {
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
}
|
|
|
|
return LUPPP_RETURN_OK;
|
|
}
|
|
|
|
|
|
int DiskReader::loadSample( int track, int scene, string path )
|
|
{
|
|
/// load the sample
|
|
SndfileHandle infile( path, SFM_READ );
|
|
int chnls = infile.channels();
|
|
std::vector<float> bufL( infile.frames() );
|
|
std::vector<float> bufR( infile.frames() );
|
|
float frameBuf[ chnls ];
|
|
|
|
if ( infile.error() ) {
|
|
LUPPP_ERROR("File %s, Error %s", path.c_str(), infile.strError() );
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
|
|
LUPPP_NOTE("Loading file with %i chnls, frames %i, bufferL size %i bufferR size %i", infile.channels(), infile.frames(), bufL.size(), bufR.size() );
|
|
|
|
// Read data
|
|
for(int f=0; f<infile.frames(); f++) {
|
|
infile.readf( frameBuf, 1 );
|
|
|
|
// Frist sapmle
|
|
// used for both channels when file is mono
|
|
// used for left channel when file is stereo
|
|
if(chnls > 0) {
|
|
bufL[f] = frameBuf[0];
|
|
bufR[f] = frameBuf[0];
|
|
}
|
|
// Second sample
|
|
// used for right channel when file is stereo
|
|
if(chnls > 1) {
|
|
bufR[f] = frameBuf[1];
|
|
}
|
|
}
|
|
|
|
/// resample?
|
|
if ( infile.samplerate() != gui->samplerate ) {
|
|
LUPPP_NOTE("%s%i%s%i", "Resampling from ", infile.samplerate(), " to ", gui->samplerate);
|
|
|
|
float resampleRatio = float(gui->samplerate) / infile.samplerate();
|
|
std::vector<float> resampledL( infile.frames() / chnls * resampleRatio );
|
|
std::vector<float> resampledR( infile.frames() / chnls * resampleRatio );
|
|
|
|
SRC_DATA dataL;
|
|
SRC_DATA dataR;
|
|
dataL.data_in = &bufL[0];
|
|
dataR.data_in = &bufR[0];
|
|
dataL.data_out = &resampledL[0];
|
|
dataR.data_out = &resampledR[0];
|
|
|
|
dataL.input_frames = infile.frames() / chnls;
|
|
dataR.input_frames = infile.frames() / chnls;
|
|
dataL.output_frames = infile.frames() / chnls * resampleRatio;
|
|
dataR.output_frames = infile.frames() / chnls * resampleRatio;
|
|
|
|
dataL.end_of_input = 0;
|
|
dataR.end_of_input = 0;
|
|
dataL.src_ratio = resampleRatio;
|
|
dataR.src_ratio = resampleRatio;
|
|
|
|
int q = SRC_SINC_FASTEST;
|
|
|
|
switch( resampleQuality ) {
|
|
case 0:
|
|
q = SRC_LINEAR;
|
|
break;
|
|
case 1:
|
|
q = SRC_SINC_FASTEST;
|
|
break;
|
|
case 2:
|
|
q = SRC_SINC_BEST_QUALITY;
|
|
break;
|
|
}
|
|
|
|
|
|
// resample quality taken from config file,
|
|
int ret = src_simple ( &dataL, q, 1 );
|
|
if ( ret == 0 )
|
|
LUPPP_NOTE("%s%i%s%i", "Resampling L finished, from ", dataL.input_frames_used, " to ", dataL.output_frames_gen );
|
|
else
|
|
LUPPP_ERROR("%s%i%s%i", "Resampling L finished, from ", dataL.input_frames_used, " to ", dataL.output_frames_gen );
|
|
ret = src_simple ( &dataR, q, 1 );
|
|
if ( ret == 0 )
|
|
LUPPP_NOTE("%s%i%s%i", "Resampling R finished, from ", dataR.input_frames_used, " to ", dataR.output_frames_gen );
|
|
else
|
|
LUPPP_ERROR("%s%i%s%i", "Resampling R finished, from ", dataR.input_frames_used, " to ", dataR.output_frames_gen );
|
|
|
|
/// exchange buffers, so buf contains the resampled audio
|
|
bufL.swap( resampledL );
|
|
bufR.swap( resampledR );
|
|
}
|
|
|
|
|
|
/// create buffer, and set the data
|
|
AudioBuffer* ab = new AudioBuffer();
|
|
ab->setAudioFrames( bufL.size() );
|
|
ab->nonRtSetSample( bufL, bufR );
|
|
|
|
//cout << "DiskReader::loadSample() " << path << endl;
|
|
|
|
bool loadableBuffer = false;
|
|
|
|
// retrieve sample metadata from sample.cfg using filename as key
|
|
const auto baseName = path.substr(path.find_last_of("/\\") + 1);
|
|
//cout << "tmp " << tmp << " baseName " << baseName << endl;
|
|
ab->setName( baseName );
|
|
|
|
if ( infile.frames() > 0 ) {
|
|
char* basePath = strdup( path.c_str() );
|
|
stringstream base;
|
|
base << dirname( basePath ) << "/audio.cfg";
|
|
|
|
free( basePath );
|
|
|
|
/// open audio.cfg, reading whole file
|
|
#ifdef DEBUG_STATE
|
|
cout << "loading sample metadata file " << base.str().c_str() << endl;
|
|
#endif
|
|
std::ifstream sampleFile( base.str().c_str(), std::ios_base::in|std::ios_base::ate);
|
|
long file_length = sampleFile.tellg();
|
|
if ( file_length > 0 ) {
|
|
sampleFile.seekg(0, std::ios_base::beg);
|
|
sampleFile.clear();
|
|
std::vector<char> sampleString(file_length + 1);
|
|
sampleFile.read(sampleString.data(), file_length);
|
|
sampleString.back() = '\0';
|
|
|
|
//cout << "Sample file:" << endl << sampleString << endl;
|
|
//cout << "Sample file (parsed):" << endl << cJSON_Parse( sampleString ) << endl;
|
|
|
|
cJSON* audioJson = cJSON_Parse( sampleString.data() );
|
|
if (!audioJson) {
|
|
LUPPP_ERROR("%s %s","Error in Sample JSON before: ", cJSON_GetErrorPtr() );
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
|
|
cJSON* sample = cJSON_GetObjectItem( audioJson, baseName.c_str() );
|
|
if ( sample ) {
|
|
cJSON* beats = cJSON_GetObjectItem( sample, "beats" );
|
|
cJSON* name = cJSON_GetObjectItem( sample, "name" );
|
|
//cout << "Clip @ " << track << " " << scene << " gets " << beats->valuedouble << " beats."<< endl;
|
|
if ( beats ) {
|
|
loadableBuffer = true;
|
|
ab->setBeats( beats->valuedouble );
|
|
}
|
|
|
|
if ( name ) {
|
|
ab->setName( name->valuestring );
|
|
}
|
|
}
|
|
|
|
// if we don't find the beats from audio.cfg, show dialog
|
|
if ( loadableBuffer == false ) {
|
|
LUPPP_NOTE("Warning: audio.cfg has no entry for beats.");
|
|
int ret = showAudioEditor( ab );
|
|
|
|
if ( ret == LUPPP_RETURN_OK ) {
|
|
// flag that we can load this sample OK
|
|
loadableBuffer = true;
|
|
} else {
|
|
delete ab;
|
|
}
|
|
}
|
|
|
|
cJSON_Delete( audioJson );
|
|
} else {
|
|
// this means there's no audio.cfg file found for the sample: show the user
|
|
// the file, and ask what the intended beat number is, and load the AudioBuffer
|
|
LUPPP_WARN("%s %s","Empty or no audio.cfg found at ",base.str().c_str() );
|
|
int error = showAudioEditor( ab );
|
|
if ( error == LUPPP_RETURN_ERROR ) {
|
|
LUPPP_WARN("cancel clicked, deleting audiobuffer" );
|
|
delete ab;
|
|
} else {
|
|
std::string name = path;
|
|
int i = name.find_last_of('/') + 1;
|
|
std::string sub = name.substr( i );
|
|
ab->setName( sub.c_str() );
|
|
|
|
LUPPP_NOTE("AudioBuffer %s set %i beats", ab->getName().c_str(), ab->getBeats() );
|
|
|
|
loadableBuffer = true;
|
|
}
|
|
}
|
|
|
|
if ( loadableBuffer ) {
|
|
std::string n = ab->getName();
|
|
|
|
// write audioBuffer to DSP
|
|
EventLooperLoad e = EventLooperLoad( track, scene, ab );
|
|
writeToDspRingbuffer( &e );
|
|
|
|
// now write audiobuffer name to GUI on track, scene
|
|
gui->getTrack( track )->getClipSelector()->clipName( scene, n );
|
|
|
|
char* tmp = strdup( path.c_str() );
|
|
lastLoadedSamplePath = dirname( tmp );
|
|
free(tmp);
|
|
} else {
|
|
LUPPP_NOTE("AudioBuffer not loaded, missing beats info and dialog was Canceled" );
|
|
}
|
|
}
|
|
|
|
return LUPPP_RETURN_OK;
|
|
|
|
}
|
|
|
|
std::string DiskReader::getLastLoadedSamplePath()
|
|
{
|
|
return lastLoadedSamplePath;
|
|
}
|
|
|
|
int DiskReader::readSession( std::string path )
|
|
{
|
|
cout << "DiskReader::readSession() " << path << endl;
|
|
sessionPath = path;
|
|
|
|
stringstream s;
|
|
s << path << "/session.luppp";
|
|
|
|
stringstream samplePath;
|
|
samplePath << path << "/audio/audio.cfg";
|
|
|
|
cout << "session path: " << s.str() << endl;
|
|
cout << "audio path: " << samplePath.str() << endl;
|
|
|
|
// open session, read all
|
|
std::ifstream file( s.str().c_str(), std::ios_base::in|std::ios_base::ate);
|
|
long file_length = file.tellg();
|
|
if ( file_length < 0 ) {
|
|
// empty file / file no exists:
|
|
LUPPP_ERROR("no session file exists!");
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
|
|
file.seekg(0, std::ios_base::beg);
|
|
file.clear();
|
|
char *sessionString = new char[file_length];
|
|
file.read(sessionString, file_length);
|
|
|
|
// create cJSON nodes from strings
|
|
sessionJson = cJSON_Parse( sessionString );
|
|
if (!sessionJson) {
|
|
LUPPP_ERROR("%s %s", "Error in Session JSON before: ", cJSON_GetErrorPtr() );
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
|
|
|
|
int tr = readTracks();
|
|
|
|
int mr = readMaster();
|
|
|
|
if( tr == mr ) {};
|
|
|
|
// cleanup
|
|
cJSON_Delete( sessionJson );
|
|
delete[] sessionString;
|
|
|
|
return LUPPP_RETURN_OK;
|
|
}
|
|
|
|
int DiskReader::readMaster()
|
|
{
|
|
cJSON* master = cJSON_GetObjectItem( sessionJson, "master");
|
|
if ( master ) {
|
|
// bpm
|
|
{
|
|
cJSON* bpm = cJSON_GetObjectItem( master, "bpm");
|
|
if ( bpm ) {
|
|
LUPPP_NOTE("%s %i","Session: BPM ",bpm->valueint);
|
|
EventTimeBPM e( bpm->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// fader
|
|
{
|
|
cJSON* fader = cJSON_GetObjectItem( master, "fader");
|
|
if ( fader ) {
|
|
EventTrackVol e( -1, fader->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// input volume
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputVolume");
|
|
if ( cjson ) {
|
|
EventMasterInputVol e( cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// input to send
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputToSndVol");
|
|
if ( cjson ) {
|
|
EventMasterInputTo e( INPUT_TO_SEND, cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// input to key
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputToXSide");
|
|
if ( cjson ) {
|
|
EventMasterInputTo e( INPUT_TO_XSIDE, cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// input to mix
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputToMixVol");
|
|
if ( cjson ) {
|
|
EventMasterInputTo e( INPUT_TO_MIX, cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
|
|
// input to send active
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputToSndActive");
|
|
if ( cjson ) {
|
|
EventMasterInputTo e( INPUT_TO_SEND, cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// input to key active
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputToKeyActive");
|
|
if ( cjson ) {
|
|
EventMasterInputTo e( INPUT_TO_SIDE_KEY, cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// input to mix active
|
|
{
|
|
cJSON* cjson = cJSON_GetObjectItem( master, "inputToMixActive");
|
|
if ( cjson ) {
|
|
EventMasterInputTo e( INPUT_TO_MIX, cjson->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
|
|
// reverb
|
|
{
|
|
cJSON* reverb = cJSON_GetObjectItem( master, "reverb");
|
|
if ( reverb ) {
|
|
cJSON* active = cJSON_GetObjectItem( reverb, "active");
|
|
cJSON* size = cJSON_GetObjectItem( reverb, "size");
|
|
cJSON* wet = cJSON_GetObjectItem( reverb, "wet");
|
|
cJSON* damping = cJSON_GetObjectItem( reverb, "damping");
|
|
|
|
if ( active && size && wet && damping ) {
|
|
EventFxReverb e( active->valuedouble, size->valuedouble,
|
|
wet->valuedouble, damping->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
} else {
|
|
#ifdef DEBUG_STATE
|
|
cout << "Session has no reverb element" << endl;
|
|
#endif
|
|
}
|
|
}
|
|
// TODO add samplerate to session JSON
|
|
|
|
// sceneNames
|
|
{
|
|
cJSON* names = cJSON_GetObjectItem( master, "sceneNames");
|
|
if ( names ) {
|
|
GMasterTrack* master = gui->getMasterTrack();
|
|
Avtk::ClipSelector* clipSelector = master->getClipSelector();
|
|
int nscenes = cJSON_GetArraySize( names );
|
|
for(int s = 0; s < nscenes; s++ ) {
|
|
cJSON* name = cJSON_GetArrayItem( names, s );
|
|
clipSelector->clipName( s, name->valuestring );
|
|
}
|
|
clipSelector->redraw();
|
|
}
|
|
}
|
|
|
|
} else {
|
|
LUPPP_ERROR("%s", "Error getting master from JSON" );
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
|
|
return LUPPP_RETURN_OK;
|
|
}
|
|
|
|
|
|
int DiskReader::readScenes(int t, cJSON* track)
|
|
{
|
|
cJSON* clips = cJSON_GetObjectItem( track, "clips");
|
|
if ( clips ) {
|
|
|
|
int nClips = cJSON_GetArraySize( clips );
|
|
for(int s = 0; s < nClips; s++ ) {
|
|
// get metadata for Clip
|
|
cJSON* clip = cJSON_GetArrayItem( clips, s );
|
|
|
|
if ( strcmp(clip->valuestring, "") != 0 ) {
|
|
stringstream sampleFilePath;
|
|
sampleFilePath << sessionPath << "/audio/" << clip->valuestring;
|
|
#ifdef DEBUG_STATE
|
|
LUPPP_NOTE << "clip t " << t << " s " << s << " path " << sampleFilePath.str() << endl;
|
|
#endif
|
|
// load it, checking for sample.cfg, and using metadata if there
|
|
loadSample( t, s, sampleFilePath.str() );
|
|
}
|
|
|
|
// FIXME: check GUI ringbuffer after each sample: with resampling it can
|
|
// take quite some time, and the ->GUI ringbuffer can fill up
|
|
handleGuiEvents();
|
|
|
|
} // nClips loop
|
|
}
|
|
|
|
return LUPPP_RETURN_OK;
|
|
}
|
|
|
|
int DiskReader::readTracks()
|
|
{
|
|
cJSON* tracks = cJSON_GetObjectItem( sessionJson, "tracks");
|
|
if ( tracks ) {
|
|
int nTracks = cJSON_GetArraySize( tracks );
|
|
for(int t = 0; t < nTracks; t++ ) {
|
|
cJSON* track = cJSON_GetArrayItem( tracks, t );
|
|
|
|
if( !track ) {
|
|
LUPPP_WARN("Track %i has no name track saved.", t);
|
|
} else {
|
|
readScenes( t, track );
|
|
|
|
// name
|
|
{
|
|
cJSON* name = cJSON_GetObjectItem( track, "name");
|
|
if( !name ) {
|
|
LUPPP_WARN("Track %i has no name data saved.", t);
|
|
} else {
|
|
gui->getTrack(t)->bg.copy_label( name->valuestring );
|
|
}
|
|
}
|
|
// fader
|
|
{
|
|
cJSON* fader = cJSON_GetObjectItem( track, "fader");
|
|
if( !fader ) {
|
|
LUPPP_WARN("Track %i has no fader data saved.", t);
|
|
} else {
|
|
EventTrackVol e( t, fader->valuedouble );
|
|
writeToDspRingbuffer( &e );
|
|
}
|
|
}
|
|
// pan
|
|
{
|
|
cJSON* pan = cJSON_GetObjectItem( track, "pan");
|
|
if( !pan ) {
|
|
LUPPP_WARN("Track %i has no pan data saved.", t);
|
|
} else {
|
|
EventTrackPan e( t, (pan->valuedouble*2)-1.f );
|
|
writeToDspRingbuffer( &e );
|
|
LUPPP_WARN("Track %i has pan %f", pan->valuedouble);
|
|
}
|
|
}
|
|
// sends
|
|
{
|
|
cJSON* send = cJSON_GetObjectItem( track, "sendAmount");
|
|
cJSON* sendActive = cJSON_GetObjectItem( track, "sendActive");
|
|
|
|
cJSON* xside = cJSON_GetObjectItem( track, "xsideAmount");
|
|
cJSON* keyActive = cJSON_GetObjectItem( track, "keyActive");
|
|
|
|
if( !send || !sendActive || !xside || !keyActive ) {
|
|
LUPPP_WARN("Track %i has no send data saved.", t);
|
|
} else {
|
|
EventTrackSendActive e1( t, SEND_POSTFADER, sendActive->valueint );
|
|
EventTrackSendActive e2( t, SEND_KEY, keyActive ->valueint );
|
|
|
|
EventTrackSend e3( t, SEND_XSIDE, xside->valuedouble );
|
|
EventTrackSend e4( t, SEND_POSTFADER, send->valuedouble );
|
|
|
|
|
|
writeToDspRingbuffer( &e1 );
|
|
writeToDspRingbuffer( &e2 );
|
|
writeToDspRingbuffer( &e3 );
|
|
}
|
|
|
|
cJSON* jacksend = cJSON_GetObjectItem( track, "jacksendAmount");
|
|
cJSON* jacksendActive = cJSON_GetObjectItem( track, "jacksendActive");
|
|
if(jacksend) {
|
|
EventTrackJackSend ev(t,jacksend->valuedouble);
|
|
writeToDspRingbuffer(&ev);
|
|
}
|
|
if(jacksendActive) {
|
|
EventTrackJackSendActivate ev(t,jacksendActive->valueint);
|
|
writeToDspRingbuffer(&ev);
|
|
}
|
|
}
|
|
}// if track
|
|
} // nTracks loop
|
|
} else {
|
|
LUPPP_ERROR("%s", "Error getting clip" );
|
|
return LUPPP_RETURN_ERROR;
|
|
}
|
|
return LUPPP_RETURN_OK;
|
|
}
|