| 
							- /*
 -   ZynAddSubFX - a software synthesizer
 - 
 -   Bank.cpp - Instrument Bank
 -   Copyright (C) 2002-2005 Nasca Octavian Paul
 -   Copyright (C) 2010-2010 Mark McCurry
 -   Author: Nasca Octavian Paul
 -           Mark McCurry
 - 
 -   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 2
 -   of the License, or (at your option) any later version.
 - */
 - 
 - #include "Bank.h"
 - #include <cstring>
 - #include <cstdio>
 - #include <cstdlib>
 - #include <dirent.h>
 - #include <sys/stat.h>
 - #include <algorithm>
 - 
 - #include <sys/types.h>
 - #include <fcntl.h>
 - #include <unistd.h>
 - #include <errno.h>
 - 
 - #include "Config.h"
 - #include "Util.h"
 - #include "Part.h"
 - #include "BankDb.h"
 - 
 - #define INSTRUMENT_EXTENSION ".xiz"
 - 
 - //if this file exists into a directory, this make the directory to be considered as a bank, even if it not contains a instrument file
 - #define FORCE_BANK_DIR_FILE ".bankdir"
 - 
 - using namespace std;
 - 
 - Bank::Bank(CarlaConfig *config)
 -     :bankpos(0), defaultinsname(" "), config(config),
 -     db(new BankDb), bank_msb(0), bank_lsb(0)
 - {
 -     clearbank();
 -     bankfiletitle = dirname;
 -     rescanforbanks();
 -     loadbank(config->cfg.currentBankDir);
 - 
 -     for(unsigned i=0; i<banks.size(); ++i) {
 -         if(banks[i].dir == config->cfg.currentBankDir) {
 -             bankpos = i;
 -             break;
 -         }
 -     }
 - }
 - 
 - Bank::~Bank()
 - {
 -     clearbank();
 -     delete db;
 - }
 - 
 - /*
 -  * Get the name of an instrument from the bank
 -  */
 - string Bank::getname(unsigned int ninstrument)
 - {
 -     if(emptyslot(ninstrument))
 -         return defaultinsname;
 -     return ins[ninstrument].name;
 - }
 - 
 - /*
 -  * Get the numbered name of an instrument from the bank
 -  */
 - string Bank::getnamenumbered(unsigned int ninstrument)
 - {
 -     if(emptyslot(ninstrument))
 -         return defaultinsname;
 - 
 -     return stringFrom(ninstrument + 1) + ". " + getname(ninstrument);
 - }
 - 
 - /*
 -  * Changes the name of an instrument (and the filename)
 -  */
 - int Bank::setname(unsigned int ninstrument, const string &newname, int newslot)
 - {
 -     if(emptyslot(ninstrument))
 -         return 0;
 - 
 -     string newfilename;
 -     char   tmpfilename[100 + 1];
 -     tmpfilename[100] = 0;
 - 
 -     if(newslot >= 0)
 -         snprintf(tmpfilename, 100, "%4d-%s", newslot + 1, newname.c_str());
 -     else
 -         snprintf(tmpfilename, 100, "%4d-%s", ninstrument + 1, newname.c_str());
 - 
 -     //add the zeroes at the start of filename
 -     for(int i = 0; i < 4; ++i)
 -         if(tmpfilename[i] == ' ')
 -             tmpfilename[i] = '0';
 - 
 -     newfilename = dirname + legalizeFilename(tmpfilename) + ".xiz";
 - 
 -     int err = rename(ins[ninstrument].filename.c_str(), newfilename.c_str());
 -     if(err)
 -         return err;
 - 
 -     ins[ninstrument].filename = newfilename;
 -     ins[ninstrument].name     = newname;
 -     return err;
 - }
 - 
 - /*
 -  * Check if there is no instrument on a slot from the bank
 -  */
 - bool Bank::emptyslot(unsigned int ninstrument)
 - {
 -     if(ninstrument >= BANK_SIZE)
 -         return true;
 -     if(ins[ninstrument].filename.empty())
 -         return true;
 - 
 -     return false;
 - }
 - 
 - /*
 -  * Removes the instrument from the bank
 -  */
 - int Bank::clearslot(unsigned int ninstrument)
 - {
 -     if(emptyslot(ninstrument))
 -         return 0;
 - 
 -     //no error when no file
 -     FILE *f = fopen(ins[ninstrument].filename.c_str(), "r");
 -     if(!f)
 -         return 0;
 -     fclose(f);
 - 
 -     int err = remove(ins[ninstrument].filename.c_str());
 -     if(!err)
 -         deletefrombank(ninstrument);
 -     return err;
 - }
 - 
 - /*
 -  * Save the instrument to a slot
 -  */
 - int Bank::savetoslot(unsigned int ninstrument, Part *part)
 - {
 -     int err = clearslot(ninstrument);
 -     if(err)
 -         return err;
 - 
 -     const int maxfilename = 200;
 -     char      tmpfilename[maxfilename + 20];
 -     ZERO(tmpfilename, maxfilename + 20);
 - 
 -     snprintf(tmpfilename,
 -              maxfilename,
 -              "%04d-%s",
 -              ninstrument + 1,
 -              (char *)part->Pname);
 - 
 -     string filename = dirname + '/' + legalizeFilename(tmpfilename) + ".xiz";
 - 
 -     FILE *f = fopen(filename.c_str(), "r");
 -     if(f) {
 -         fclose(f);
 - 
 -         err = remove(filename.c_str());
 -         if(err)
 -             return err;
 -     }
 - 
 -     err = part->saveXML(filename.c_str());
 -     if(err)
 -         return err;
 -     addtobank(ninstrument, legalizeFilename(tmpfilename) + ".xiz",
 -               (char *) part->Pname);
 -     return 0;
 - }
 - 
 - /*
 -  * Loads the instrument from the bank
 -  */
 - int Bank::loadfromslot(unsigned int ninstrument, Part *part)
 - {
 -     if(emptyslot(ninstrument))
 -         return 0;
 - 
 -     part->AllNotesOff();
 -     part->defaultsinstrument();
 - 
 -     part->loadXMLinstrument(ins[ninstrument].filename.c_str());
 -     return 0;
 - }
 - 
 - /*
 -  * Makes current a bank directory
 -  */
 - int Bank::loadbank(string bankdirname)
 - {
 -     normalizedirsuffix(bankdirname);
 -     DIR *dir = opendir(bankdirname.c_str());
 -     clearbank();
 - 
 -     if(dir == NULL)
 -         return -1;
 - 
 -     //set msb when possible
 -     bank_msb = 0;
 -     for(unsigned i=0; i<banks.size(); i++)
 -         if(banks[i].dir == bankdirname)
 -             bank_msb = i;
 - 
 -     dirname = bankdirname;
 - 
 -     bankfiletitle = dirname;
 - 
 -     struct dirent *fn;
 - 
 -     while((fn = readdir(dir))) {
 -         const char *filename = fn->d_name;
 - 
 -         //check for extension
 -         if(strstr(filename, INSTRUMENT_EXTENSION) == NULL)
 -             continue;
 - 
 -         //verify if the name is like this NNNN-name (where N is a digit)
 -         int no = 0;
 -         unsigned int startname = 0;
 - 
 -         for(unsigned int i = 0; i < 4; ++i) {
 -             if(strlen(filename) <= i)
 -                 break;
 - 
 -             if((filename[i] >= '0') && (filename[i] <= '9')) {
 -                 no = no * 10 + (filename[i] - '0');
 -                 startname++;
 -             }
 -         }
 - 
 -         if((startname + 1) < strlen(filename))
 -             startname++;  //to take out the "-"
 - 
 -         string name = filename;
 - 
 -         //remove the file extension
 -         for(int i = name.size() - 1; i >= 2; i--)
 -             if(name[i] == '.') {
 -                 name = name.substr(0, i);
 -                 break;
 -             }
 - 
 -         if(no != 0) //the instrument position in the bank is found
 -             addtobank(no - 1, filename, name.substr(startname));
 -         else
 -             addtobank(-1, filename, name);
 -     }
 - 
 -     closedir(dir);
 - 
 -     if(!dirname.empty())
 -         config->cfg.currentBankDir = dirname;
 - 
 -     return 0;
 - }
 - 
 - /*
 -  * Makes a new bank, put it on a file and makes it current bank
 -  */
 - int Bank::newbank(string newbankdirname)
 - {
 -     string bankdir;
 -     bankdir = config->cfg.bankRootDirList[0];
 - 
 -     expanddirname(bankdir);
 -     normalizedirsuffix(bankdir);
 - 
 -     bankdir += newbankdirname;
 - #ifdef _WIN32
 -     if(mkdir(bankdir.c_str()) < 0)
 - #else
 -     if(mkdir(bankdir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0)
 - #endif
 -         return -1;
 - 
 -     const string tmpfilename = bankdir + '/' + FORCE_BANK_DIR_FILE;
 - 
 -     FILE *tmpfile = fopen(tmpfilename.c_str(), "w+");
 -     fclose(tmpfile);
 - 
 -     return loadbank(bankdir);
 - }
 - 
 - /*
 -  * Check if the bank is locked (i.e. the file opened was readonly)
 -  */
 - int Bank::locked()
 - {
 -     //XXX Fixme
 -     return dirname.empty();
 - }
 - 
 - /*
 -  * Swaps a slot with another
 -  */
 - int Bank::swapslot(unsigned int n1, unsigned int n2)
 - {
 -     int err = 0;
 -     if((n1 == n2) || (locked()))
 -         return 0;
 -     if(emptyslot(n1) && (emptyslot(n2)))
 -         return 0;
 -     if(emptyslot(n1)) //change n1 to n2 in order to make
 -         swap(n1, n2);
 - 
 -     if(emptyslot(n2)) { //this is just a movement from slot1 to slot2
 -         err |= setname(n1, getname(n1), n2);
 -         if(err)
 -             return err;
 -         ins[n2] = ins[n1];
 -         ins[n1] = ins_t();
 -     }
 -     else {  //if both slots are used
 -         if(ins[n1].name == ins[n2].name) //change the name of the second instrument if the name are equal
 -             ins[n2].name += "2";
 - 
 -         err |= setname(n1, getname(n1), n2);
 -         err |= setname(n2, getname(n2), n1);
 -         if(err)
 -             return err;
 -         swap(ins[n2], ins[n1]);
 -     }
 -     return err;
 - }
 - 
 - 
 - bool Bank::bankstruct::operator<(const bankstruct &b) const
 - {
 -     return name < b.name;
 - }
 - 
 - /*
 -  * Re-scan for directories containing instrument banks
 -  */
 - 
 - void Bank::rescanforbanks()
 - {
 -     db->clear();
 -     //remove old banks
 -     banks.clear();
 - 
 -     for(int i = 0; i < MAX_BANK_ROOT_DIRS; ++i)
 -         if(!config->cfg.bankRootDirList[i].empty())
 -             scanrootdir(config->cfg.bankRootDirList[i]);
 - 
 -     //sort the banks
 -     sort(banks.begin(), banks.end());
 - 
 -     for(int i = 0; i < (int) banks.size(); ++i)
 -         db->addBankDir(banks[i].dir);
 - 
 -     //remove duplicate bank names
 -     for(int j = 0; j < (int) banks.size() - 1; ++j) {
 -         int dupl = 0;
 -         for(int i = j + 1; i < (int) banks.size(); ++i) {
 -             if(banks[i].name == banks[j].name) {
 -                 //add a [1] to the first bankname and [n] to others
 -                 banks[i].name = banks[i].name + '['
 -                                 + stringFrom(dupl + 2) + ']';
 -                 dupl++;
 -             }
 -         }
 -         if(dupl != 0)
 -             banks[j].name += "[1]";
 -         if(dupl)
 -             j += dupl;
 -     }
 -     db->scanBanks();
 - }
 - 
 - void Bank::setMsb(uint8_t msb)
 - {
 -     if(msb < banks.size() && banks[msb].dir != bankfiletitle)
 -         loadbank(banks[msb].dir);
 - }
 - 
 - void Bank::setLsb(uint8_t lsb)
 - {
 -     //should only involve values of 0/1 for the time being...
 -     bank_lsb = limit<uint8_t>(lsb,0,1);
 - }
 - 
 - 
 - // private stuff
 - 
 - void Bank::scanrootdir(string rootdir)
 - {
 -     expanddirname(rootdir);
 - 
 -     DIR *dir = opendir(rootdir.c_str());
 -     if(dir == NULL)
 -         return;
 - 
 -     bankstruct bank;
 - 
 -     const char *separator = "/";
 -     if(rootdir.size()) {
 -         char tmp = rootdir[rootdir.size() - 1];
 -         if((tmp == '/') || (tmp == '\\'))
 -             separator = "";
 -     }
 - 
 -     struct dirent *fn;
 -     while((fn = readdir(dir))) {
 -         const char *dirname = fn->d_name;
 -         if(dirname[0] == '.')
 -             continue;
 - 
 -         bank.dir  = rootdir + separator + dirname + '/';
 -         bank.name = dirname;
 -         //find out if the directory contains at least 1 instrument
 -         bool isbank = false;
 - 
 -         DIR *d = opendir(bank.dir.c_str());
 -         if(d == NULL)
 -             continue;
 - 
 -         struct dirent *fname;
 - 
 -         while((fname = readdir(d))) {
 -             if((strstr(fname->d_name, INSTRUMENT_EXTENSION) != NULL)
 -                || (strstr(fname->d_name, FORCE_BANK_DIR_FILE) != NULL)) {
 -                 isbank = true;
 -                 break; //could put a #instrument counter here instead
 -             }
 -         }
 - 
 -         if(isbank)
 -             banks.push_back(bank);
 - 
 -         closedir(d);
 -     }
 - 
 -     closedir(dir);
 - }
 - 
 - void Bank::clearbank()
 - {
 -     for(int i = 0; i < BANK_SIZE; ++i)
 -         ins[i] = ins_t();
 - 
 -     bankfiletitle.clear();
 -     dirname.clear();
 - }
 - 
 - std::vector<std::string> Bank::search(std::string s) const
 - {
 -     std::vector<std::string> out;
 -     auto vec = db->search(s);
 -     for(auto e:vec) {
 -         out.push_back(e.name);
 -         out.push_back(e.bank+e.file);
 -     }
 -     return out;
 - }
 - 
 - std::vector<std::string> Bank::blist(std::string s)
 - {
 -     std::vector<std::string> out;
 -     int result = loadbank(s);
 -     for(int i=0; i<128; ++i) {
 -         if(ins[i].filename.empty())
 -             out.push_back("Empty Preset");
 -         else
 -             out.push_back(ins[i].name);
 -         out.push_back(to_s(i));
 -     }
 -     return out;
 - }
 - 
 - int Bank::addtobank(int pos, string filename, string name)
 - {
 -     if((pos >= 0) && (pos < BANK_SIZE)) {
 -         if(!ins[pos].filename.empty())
 -             pos = -1;  //force it to find a new free position
 -     }
 -     else
 -     if(pos >= BANK_SIZE)
 -         pos = -1;
 - 
 - 
 -     if(pos < 0)   //find a free position
 -         for(int i = BANK_SIZE - 1; i >= 0; i--)
 -             if(ins[i].filename.empty()) {
 -                 pos = i;
 -                 break;
 -             }
 - 
 -     if(pos < 0)
 -         return -1;  //the bank is full
 - 
 -     deletefrombank(pos);
 - 
 -     ins[pos].name     = name;
 -     ins[pos].filename = dirname + filename;
 -     return 0;
 - }
 - 
 - void Bank::deletefrombank(int pos)
 - {
 -     if((pos < 0) || (pos >= BANK_SIZE))
 -         return;
 -     ins[pos] = ins_t();
 - }
 - 
 - Bank::ins_t::ins_t()
 -     :name(""), filename("")
 - {}
 - 
 - void Bank::expanddirname(std::string &dirname) {
 -     if (dirname.empty())
 -         return;
 - 
 -     // if the directory name starts with a ~ and the $HOME variable is
 -     // defined in the environment, replace ~ by the content of $HOME
 -     if (dirname.at(0) == '~') {
 -         char *home_dirname = getenv("HOME");
 -         if (home_dirname != NULL) {
 -             dirname = std::string(home_dirname) + dirname.substr(1);
 -         }
 -     }
 - }
 - 
 - void Bank::normalizedirsuffix(string &dirname) const {
 -     if(((dirname[dirname.size() - 1]) != '/')
 -        && ((dirname[dirname.size() - 1]) != '\\'))
 -         dirname += "/";
 - }
 
 
  |