//Standard lib #include #include #include #include #include #include #include //Third party #include "raylib.h" #include "jRead.h" //included in our source https://www.codeproject.com/Articles/885389/jRead-An-in-place-JSON-Element-Reader #include "jWrite.h" //included in our source https://www.codeproject.com/Articles/887604/jWrite-A-Really-Simple-JSON-Writer-in-C //Our own files #include "constants.h" #include "programstate.h" #include "drawhelper.h" #include "draw.h" #define SAVE_BUFFER_LEN 1024*1024*4 //4 MB to be on the safe side. This is just RAM, not the file size. ProgramState programState; //global singleton state. All other files use extern ProgramState programState; void setColorPalette(int number) { //First set Background to default, in case a palette only works with notes. //Otherwise the palette can overwrite. srand(time(0)); programState.colors[VIS_PORTS+0] = (Color){ 45, 50, 57, 255 }; //LSS Background color. The general background, lowest layer. programState.colors[VIS_PORTS+1] = (Color){ 55, 61, 69, 127 }; //used for note backgrounds programState.colors[VIS_PORTS+2] = (Color){ 65, 65, 65, 200 }; //e.g. pitch marker switch (number) { case 1: //random notes. Background default for (int i=0; i= 1. multiplied with time of one frame (0.016s @ 60fps). Factor 3 is the same as bpm fadeout with 120bpm programState.showConnectedPortnames = true; programState.includeClientInPortNameDisplay = false; programState.alwaysShowClock = false; programState.applicationWindowVisible = true; //for nsm //.camera is not saved, but we will save the values individually programState.camera.zoom = 1.0f; programState.camera.rotation = 0.0f; programState.cameraCenterOnX = 0; programState.cameraCenterOnY = 0; programState.pitchMin = 0+2*12; //Note Drawing Range for all modes programState.pitchMax = 127-2*12; //Pitch is inclusive. Note Drawing Range for all modes //Layer Switches. Also see enum in constants.h programState.showBackgroundImageLayer = false; //or plain color programState.showEffectLayer = true; programState.showSpriteLayer = true; programState.showDrawMode = true; //Layer Modes and Settings //char * backgroundImagePath; programState.drawMode = 0; setColorPalette(0); //For specific modes only programState.meterbridge_grouping = 1; // 127 / 1 as default -> show all notes individually. 12 would mean show activity in one octave as the same rectangle. pitchmarker is the root note. //Images and paths programState.pathBackgroundImage = ""; //set by load or draw.h. This is a path, not the texture. //Not Saved programState.clockString = malloc (sizeof(char) * 255); //set by jack programState.guiRedrawNeeded = true; //screen size or drawing configuration changed programState.instructedToQuit = false; //internal signal for the quit button programState.guiVisible = false; //Press ESC programState.bpm = 0.0d; //set by jack //programState.transportRolling; programState.modeDescription = ""; // \n for line break. Label to describe a mode. Set by files like draw_port_grids.c etc. //programState.connectedPortNames #empty programState.portActivity[VIS_PORTS]; programState.lockInput = false; //Prevent keypresses while in file open dialog etc. //Not saved but provided or changed by NSM or args programState.name = strdup(programName); if (nsm) { programState.nsmDirectory = strdup(filePath); //Our directory in NSM, empty standalone. Don't use for checks, use bool programState.nsm instead programState.filePath = malloc (sizeof(char) * 4096); //4096 is the max path length in linux snprintf(programState.filePath, (sizeof(char) * 4096), "%s/%s", filePath, "tgvssave.json"); mkdir(programState.nsmDirectory, 0755); //let silently fail if already exists. We need the dir to symlink image files. } else { programState.filePath = strdup(filePath); //This is always the direct json save file. } loadStateFromFile(); } void loadStateFromFile() { //call only after initProgramState if (programState.nsm) { } if (programState.filePath && programState.filePath[0] != '\0') { char * buffer; buffer = LoadFileText(programState.filePath); // Load text data from file (read), returns a '\0' terminated string //Begin de-serializing save data if (buffer) { //printf("%s\n", buffer); //print whole json file. //A third parameter NULL is for jRead query params and recommended as default programState.showPitchMarker = (bool)jRead_int(buffer, "{'showPitchMarker'", NULL); programState.pitchMarkerValue = jRead_int(buffer, "{'pitchMarkerValue'", NULL); programState.showPortBackground = (bool)jRead_int(buffer, "{'showPortBackground'", NULL); programState.showPortBackgroundForUnconnected = (bool)jRead_int(buffer, "{'showPortBackgroundForUnconnected'", NULL); programState.fadeOutMode = jRead_int(buffer, "{'fadeOutMode'", NULL); programState.fadeOutFactor = jRead_int(buffer, "{'fadeOutFactor'", NULL); programState.showConnectedPortnames = (bool)jRead_int(buffer, "{'showConnectedPortnames'", NULL); programState.includeClientInPortNameDisplay = (bool)jRead_int(buffer, "{'includeClientInPortNameDisplay'", NULL); programState.alwaysShowClock = (bool)jRead_int(buffer, "{'alwaysShowClock'", NULL); programState.applicationWindowVisible = (bool)jRead_int(buffer, "{'applicationWindowVisible'", NULL); programState.cameraCenterOnX = jRead_int(buffer, "{'cameraCenterOnX'", NULL); programState.cameraCenterOnY = jRead_int(buffer, "{'cameraCenterOnY'", NULL); programState.camera.zoom = (float)jRead_double(buffer, "{'camera.zoom'", NULL); programState.camera.rotation = (float)jRead_double(buffer, "{'camera.rotation'", NULL); programState.pitchMin = jRead_int(buffer, "{'pitchMin'", NULL); programState.pitchMax = jRead_int(buffer, "{'pitchMax'", NULL); programState.meterbridge_grouping = jRead_int(buffer, "{'meterbridge_grouping'", NULL); programState.drawMode = jRead_int(buffer, "{'drawMode'", NULL); programState.showBackgroundImageLayer = (bool)jRead_int(buffer, "{'showBackgroundImageLayer'", NULL); programState.showEffectLayer = (bool)jRead_int(buffer, "{'showEffectLayer'", NULL); programState.showSpriteLayer = (bool)jRead_int(buffer, "{'showSpriteLayer'", NULL); programState.showDrawMode = (bool)jRead_int(buffer, "{'showDrawMode'", NULL); //int jRead_string( char *pJson, char *pQuery, char *pDest, int destlen, int *queryParams ); char bgimgpath[4096]; jRead_string(buffer, "{'pathBackgroundImage'", bgimgpath, 4096 , NULL); loadBackgroundImage(bgimgpath, false); //sets programState.pathBackgroundImage char colorKey[64]; for (int i=0; i<19; i++) { sprintf(colorKey, "{'colors_%i'", i); //Thanks jRead! we saved the color value as string, because the long-write function does not exist. But luckily it parses everything back during read :). programState.colors[i] = GetColor(jRead_long(buffer, colorKey, NULL)); } } else { printf("Unable to open %s. Starting with default program state. Expected for first run.\n", programState.filePath); } } else { printf("No filepath present. Not loading anything, every setting is temporary.\n"); } } void saveStateToFile() { //call only after initProgramState if (programState.filePath && programState.filePath[0] != '\0') { char buffer[SAVE_BUFFER_LEN]; int returnJWCode; jwOpen( buffer, SAVE_BUFFER_LEN, JW_OBJECT, JW_PRETTY ); // open root node as object //jwObj_string( "key", "value" ); jwObj_int( "showPitchMarker", (int)programState.showPitchMarker ); jwObj_int( "pitchMarkerValue", programState.pitchMarkerValue ); jwObj_int( "showPortBackground", (int)programState.showPortBackground ); jwObj_int( "showPortBackgroundForUnconnected", (int)programState.showPortBackgroundForUnconnected ); jwObj_int( "fadeOutMode", programState.fadeOutMode ); jwObj_int( "fadeOutFactor", programState.fadeOutFactor ); jwObj_int( "showConnectedPortnames", (int)programState.showConnectedPortnames ); jwObj_int( "includeClientInPortNameDisplay", (int)programState.includeClientInPortNameDisplay ); jwObj_int( "alwaysShowClock", (int)programState.alwaysShowClock ); jwObj_int( "applicationWindowVisible", (int)programState.applicationWindowVisible ); jwObj_int( "cameraCenterOnX", programState.cameraCenterOnX ); jwObj_int( "cameraCenterOnY", programState.cameraCenterOnY ); jwObj_double( "camera.zoom", (double)programState.camera.zoom ); jwObj_double( "camera.rotation", (double)programState.camera.rotation ); jwObj_int( "pitchMin", programState.pitchMin ); jwObj_int( "pitchMax", programState.pitchMax ); jwObj_int( "meterbridge_grouping", programState.meterbridge_grouping ); jwObj_int( "drawMode", programState.drawMode ); jwObj_int( "showBackgroundImageLayer", (int)programState.showBackgroundImageLayer ); jwObj_int( "showEffectLayer", (int)programState.showEffectLayer ); jwObj_int( "showSpriteLayer", (int)programState.showSpriteLayer ); jwObj_int( "showDrawMode", (int)programState.showDrawMode ); jwObj_string( "pathBackgroundImage", programState.pathBackgroundImage ); char colorKey[64]; char colorValue[256]; for (int i=0; i<19; i++) { sprintf(colorKey, "colors_%i", i); sprintf(colorValue, "%li", ColorToInt(programState.colors[i])); jwObj_string( colorKey, colorValue ); } returnJWCode = jwClose(); SaveFileText(programState.filePath, buffer); // Save text data to file (write), string must be '\0' terminated } }