Loopp/src/diskwriter.cxx

350 lines
11 KiB
C++
Raw Normal View History

2013-09-03 20:35:43 +02:00
#include "diskwriter.hxx"
#include "config.hxx"
#include <sstream>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <sys/stat.h>
#include "gui.hxx"
#include "gmastertrack.hxx"
#include "controller/genericmidi.hxx"
#include <sndfile.hh>
extern Gui* gui;
using namespace std;
2013-09-03 20:35:43 +02:00
DiskWriter::DiskWriter()
{
2013-09-23 10:42:08 +02:00
sessionJson = cJSON_CreateObject();
audioJson = cJSON_CreateObject();
2013-09-18 12:46:25 +02:00
2013-09-23 10:35:02 +02:00
sessionDir = getenv("HOME");
2013-09-18 12:46:25 +02:00
sessionName = "lupppSession";
2013-09-23 10:35:02 +02:00
foldersCreated = false;
2013-09-03 20:35:43 +02:00
};
void DiskWriter::initialize(std::string path, std::string name )
2013-09-03 20:35:43 +02:00
{
sessionName = name;
2013-09-23 12:54:54 +02:00
sessionPath = path;
2013-09-23 10:35:02 +02:00
// write session.luppp JSON node to <path>/<sessionName>.luppp
stringstream sessionDirStream;
sessionDirStream << path;
if ( !gui->getNsm() )
sessionDirStream << "/" << sessionName;
2013-09-23 10:35:02 +02:00
sessionDir = sessionDirStream.str();
LUPPP_NOTE( "Creating session dir %s", sessionDir.c_str() );
2013-09-23 10:35:02 +02:00
int sessionDirError = mkdir( sessionDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
if ( sessionDirError )
{
// handle by using different filename?
LUPPP_WARN("Error creating session directory");
2013-09-23 10:35:02 +02:00
}
2013-09-23 10:42:08 +02:00
stringstream audioDirStream;
audioDirStream << sessionDir << "/audio";
audioDir = audioDirStream.str();
LUPPP_NOTE("Creating audio dir %s", audioDir.c_str() );
2013-09-23 10:35:02 +02:00
2013-09-23 10:42:08 +02:00
int audioDirError = mkdir( audioDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
2013-09-23 10:35:02 +02:00
// FIXME: error check mkdir for error return
2013-09-23 10:42:08 +02:00
if ( audioDirError )
2013-09-23 10:35:02 +02:00
{
LUPPP_WARN("Error creating sample directory");
2013-09-23 10:35:02 +02:00
}
foldersCreated = true;
}
2013-09-18 12:46:25 +02:00
std::string DiskWriter::getLastSaveName()
{
return sessionName;
}
std::string DiskWriter::getLastSavePath()
{
2013-09-23 12:54:54 +02:00
return sessionPath;
2013-09-18 12:46:25 +02:00
}
int DiskWriter::writeControllerFile(std::string name ,
std::string author,
std::string link ,
Controller* c )
{
// check if controller of ID is actually a GenericMIDI controller
GenericMIDI* g = dynamic_cast<GenericMIDI*>( c );
if ( g )
{
LUPPP_NOTE("Writing .ctlr file...");
2013-10-19 14:16:16 +02:00
cJSON* controllerJson = cJSON_CreateObject();
cJSON_AddItemToObject ( controllerJson, "name", cJSON_CreateString( name.c_str() ));
cJSON_AddItemToObject ( controllerJson, "author", cJSON_CreateString( author.c_str() ));
cJSON_AddItemToObject ( controllerJson, "link", cJSON_CreateString( link.c_str() ));
// input bindings
std::vector<Binding*> b = g->getMidiToAction();
cJSON* inputBindings = cJSON_CreateArray();
cJSON_AddItemToObject(controllerJson, "inputBindings", inputBindings );
for(unsigned int i = 0; i < b.size(); i++ )
{
// create binding
cJSON* binding = cJSON_CreateObject();
cJSON_AddItemToArray( inputBindings, binding );
// add metadata to binding
const char* actionName = Event::getPrettyName( b.at(i)->action );
if ( actionName )
{
cJSON_AddItemToObject( binding, "action", cJSON_CreateString( actionName ) );
cJSON_AddNumberToObject( binding, "status", b.at(i)->status );
cJSON_AddNumberToObject( binding, "data" , b.at(i)->data );
cJSON_AddNumberToObject( binding, "track" , b.at(i)->track );
cJSON_AddNumberToObject( binding, "scene" , b.at(i)->scene );
cJSON_AddNumberToObject( binding, "send" , b.at(i)->send );
cJSON_AddNumberToObject( binding, "active", b.at(i)->active );
LUPPP_NOTE("Creating Binding: action %i == %s!", b.at(i)->action, actionName );
}
else
{
LUPPP_WARN("Binding action %i has no prettyName!", b.at(i)->action );
}
2013-10-19 14:16:16 +02:00
}
//std::vector<Binding*> b = g->getMidiToAction();
cJSON* outputBindings = cJSON_CreateArray();
cJSON_AddItemToObject(controllerJson, "outputBindings", outputBindings );
/*
for(unsigned int i = 0; i < b.size(); i++ )
{
// create binding
cJSON* binding = cJSON_CreateObject();
cJSON_AddItemToArray( outputBindings, binding );
// add metadata to binding
// FIXME: get action string from Event class: need to move function from GenericMIDI to there
cJSON_AddItemToObject( binding, "action", cJSON_CreateString( "gridlogic:launchscene" ) );
cJSON_AddNumberToObject( binding, "status", b.at(i)->status );
cJSON_AddNumberToObject( binding, "data" , b.at(i)->data );
cJSON_AddNumberToObject( binding, "track" , b.at(i)->track );
cJSON_AddNumberToObject( binding, "scene" , b.at(i)->scene );
cJSON_AddNumberToObject( binding, "send" , b.at(i)->send );
cJSON_AddNumberToObject( binding, "active", b.at(i)->active );
}
*/
2013-10-19 14:16:16 +02:00
// write the sample JSON node to <samplePath>/sample.cfg
stringstream controllerCfgPath;
controllerCfgPath << getenv("HOME") << "/.config/openAV/luppp/controllers/" << g->getName() << ".ctlr";
2013-10-19 14:16:16 +02:00
ofstream controllerCfgFile;
controllerCfgFile.open ( controllerCfgPath.str().c_str() );
controllerCfgFile << cJSON_Print( controllerJson );
controllerCfgFile.close();
}
else
{
if ( c )
LUPPP_WARN("Invalid Controller pointer: cannot write %s as is not a GenericMIDI controller!", c->getName().c_str() );
else
LUPPP_WARN("Invalid Controller pointer: was passed NULL!" );
return LUPPP_RETURN_ERROR;
}
return LUPPP_RETURN_OK;
}
int DiskWriter::writeAudioBuffer(int track, int scene, AudioBuffer* ab )
{
2013-09-23 10:35:02 +02:00
if ( !foldersCreated )
{
LUPPP_WARN("%s", "Session folders not created yet, while trying to write audioBuffers.");
return LUPPP_RETURN_ERROR;
}
stringstream filename;
filename << "t_" << track << "_s_" << scene << ".wav";
// store the clip in clipData, we will write the session JSON for it in writeSession
clipData.push_back( ClipData( track, scene, filename.str() ) );
// add the AudioBuffer metadata to the sample JSON node
cJSON* sampleClip = cJSON_CreateObject();
2013-09-23 10:42:08 +02:00
cJSON_AddItemToObject(audioJson, filename.str().c_str(), sampleClip );
cJSON_AddNumberToObject(sampleClip,"beats", ab->getBeats() );
2013-11-03 15:12:42 +01:00
// get pretty name from GUI
std::string clipName = gui->getTrack(track)->getClipSelector()->clipName( scene );
cJSON_AddItemToObject ( sampleClip, "name", cJSON_CreateString( clipName.c_str() ));
2013-09-23 10:42:08 +02:00
// write the AudioBuffer contents to <path>/audio/ as <name>.wav
2013-09-03 20:35:43 +02:00
// or alternatively t_<track>_s_<scene>.wav
2013-09-05 23:35:48 +02:00
stringstream path;
2013-09-23 10:42:08 +02:00
path << audioDir << "/" << filename.str();
SndfileHandle outfile( path.str(), SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 1, gui->samplerate );
2013-09-06 00:07:19 +02:00
// FIXME: the size of the buffer is bigger than the audio contained in it:
// calculate the length that needs saving using getBeats() * framesPerBeat
if ( ab->getAudioFrames() > 0 )
outfile.write( &ab->getData()[0], ab->getAudioFrames() );
else
{
LUPPP_WARN("%s","Sample has zero samples");
}
return LUPPP_RETURN_OK;
2013-09-03 20:35:43 +02:00
}
void DiskWriter::writeMaster()
{
// Master track stuff
cJSON* masterTrack = cJSON_CreateObject();
2013-09-23 10:42:08 +02:00
cJSON_AddItemToObject(sessionJson, "master", masterTrack );
GMasterTrack* master = gui->getMasterTrack();
cJSON_AddNumberToObject( masterTrack, "fader", master->getVolume()->value() );
cJSON_AddNumberToObject( masterTrack, "bpm", gui->getMasterTrack()->getBpm() );
2013-09-17 14:11:11 +02:00
// TODO add samplerate to session JSON
//cJSON_AddNumberToObject( masterTrack, "samplerate", gui->getMasterTrack()->getBpm() );
// scene names
Avtk::ClipSelector* clipSelector = master->getClipSelector();
cJSON* sceneNames = cJSON_CreateArray();
cJSON_AddItemToObject( masterTrack, "sceneNames", sceneNames );
for(int i = 0; i < NSCENES; i++)
{
cJSON* sceneName = cJSON_CreateString( clipSelector->clipName(i).c_str() );
cJSON_AddItemToArray( sceneNames, sceneName );
}
}
int DiskWriter::writeSession()
2013-09-03 20:35:43 +02:00
{
2013-09-23 10:35:02 +02:00
if ( !foldersCreated )
{
LUPPP_WARN("%s", "Session folders not created yet, while trying to write session.");
return LUPPP_RETURN_ERROR;
}
2013-09-05 15:05:36 +02:00
// add session metadata
2013-09-23 10:42:08 +02:00
cJSON_AddItemToObject ( sessionJson, "session", cJSON_CreateString( sessionName.c_str() ));
2013-09-05 23:35:48 +02:00
2013-09-23 10:42:08 +02:00
cJSON_AddNumberToObject( sessionJson, "version_major", 1 );
cJSON_AddNumberToObject( sessionJson, "version_minor", 0 );
cJSON_AddNumberToObject( sessionJson, "version_patch", 0 );
2013-09-05 15:05:36 +02:00
writeMaster();
2013-09-05 15:05:36 +02:00
// add JSON "tracks" array
cJSON* trackArray = cJSON_CreateArray();
2013-09-23 10:42:08 +02:00
cJSON_AddItemToObject(sessionJson, "tracks", trackArray );
// write tracks into JSON tracks array
for(int t = 0; t < NTRACKS; t++)
{
cJSON* track = cJSON_CreateObject();
cJSON_AddItemToArray( trackArray, track );
// add track metadata: volumes, sends etc
cJSON_AddNumberToObject( track, "ID", t );
2013-09-11 00:57:47 +02:00
cJSON_AddStringToObject( track, "name", gui->getTrack(t)->bg.getLabel() );
2013-09-06 01:39:01 +02:00
cJSON_AddNumberToObject( track, "fader", gui->getTrack(t)->getVolume()->value() );
cJSON_AddNumberToObject( track, "sendAmount" , gui->getTrack(t)->getSend() );
cJSON_AddNumberToObject( track, "sendActive" , gui->getTrack(t)->getSendActive() );
cJSON_AddNumberToObject( track, "xsideAmount", gui->getTrack(t)->getXSide() );
cJSON_AddNumberToObject( track, "keyActive" , gui->getTrack(t)->getKeyActive() );
// write clipData vector into clip placeholder
cJSON* clips = cJSON_CreateArray();
cJSON_AddItemToObject( track, "clips", clips );
for(int s = 0; s < NSCENES; s++)
{
// add empty string to array
cJSON* clip = cJSON_CreateString( "" );
cJSON_AddItemToArray( clips, clip );
// replace blank string if clip exists
for(unsigned int i = 0; i < clipData.size(); i++)
{
if ( clipData.at(i).track == t &&
clipData.at(i).scene == s )
{
cJSON* newClip = cJSON_CreateString( clipData.at(i).name.c_str() );
cJSON_ReplaceItemInArray( clips, s, newClip );
}
}
}
}
2013-09-20 12:30:19 +02:00
stringstream sessionLuppp;
2013-09-23 10:35:02 +02:00
sessionLuppp << sessionDir << "/session.luppp";
2013-11-02 00:31:18 +01:00
//c out << "Session dir: " << sessionDir.str() << "\n" << "Sample dir : " << audioDir.str() << endl;
ofstream sessionFile;
sessionFile.open ( sessionLuppp.str().c_str() );
2013-09-23 10:42:08 +02:00
sessionFile << cJSON_Print( sessionJson );
sessionFile.close();
2013-09-23 10:35:02 +02:00
// write the sample JSON node to <samplePath>/sample.cfg
2013-09-23 10:42:08 +02:00
stringstream audioCfg;
audioCfg << audioDir << "/audio.cfg";
2013-09-23 10:42:08 +02:00
ofstream audioCfgFile;
audioCfgFile.open ( audioCfg.str().c_str() );
audioCfgFile << cJSON_Print( audioJson );
audioCfgFile.close();
2013-09-03 20:35:43 +02:00
// clear the clipData, clean page for next save
clipData.clear();
2013-09-18 14:54:59 +02:00
// reset the cJSON objects
2013-09-23 10:42:08 +02:00
cJSON_Delete( sessionJson );
cJSON_Delete( audioJson );
2013-09-18 14:54:59 +02:00
2013-09-23 10:42:08 +02:00
sessionJson = cJSON_CreateObject();
audioJson = cJSON_CreateObject();
2013-09-18 14:54:59 +02:00
return LUPPP_RETURN_OK;
2013-09-03 20:35:43 +02:00
}