home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 November / CMCD1104.ISO / Software / Complet / ZynAddFX / Setup_ZynAddSubFX-2.1.1.exe / Bank.C < prev    next >
Encoding:
C/C++ Source or Header  |  2004-08-27  |  13.1 KB  |  526 lines

  1. /*
  2.   ZynAddSubFX - a software synthesizer
  3.  
  4.   Bank.h - Instrument Bank 
  5.   Copyright (C) 2002-2004 Nasca Octavian Paul
  6.   Author: Nasca Octavian Paul
  7.  
  8.   This program is free software; you can redistribute it and/or modify
  9.   it under the terms of version 2 of the GNU General Public License 
  10.   as published by the Free Software Foundation.
  11.  
  12.   This program is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License (version 2) for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License (version 2)
  18.   along with this program; if not, write to the Free Software Foundation,
  19.   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20.  
  21. */
  22.  
  23. #include "Bank.h"
  24. #include <string.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <dirent.h>
  28. #include <sys/stat.h>
  29.  
  30. #include <sys/types.h>
  31. #include <fcntl.h>
  32. #include <unistd.h>
  33. #include <errno.h>
  34.  
  35. #include "Config.h"
  36.  
  37. #define INSTRUMENT_EXTENSION ".xiz"
  38.  
  39. //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
  40. #define FORCE_BANK_DIR_FILE ".bankdir"
  41.  
  42. Bank::Bank(){
  43.  
  44.  
  45.     ZERO(defaultinsname,PART_MAX_NAME_LEN);
  46.     snprintf(defaultinsname,PART_MAX_NAME_LEN,"%s"," ");
  47.         
  48.     for (int i=0;i<BANK_SIZE;i++){
  49.     ins[i].used=false;
  50.     ins[i].filename=NULL;
  51.     ins[i].info.PADsynth_used=false;
  52.     };
  53.     dirname=NULL;
  54.     clearbank();
  55.  
  56.  
  57.  
  58.     for (int i=0;i<MAX_NUM_BANKS;i++){
  59.     banks[i].dir=NULL;
  60.     banks[i].name=NULL;
  61.     };
  62.     
  63.     bankfiletitle=dirname;
  64.  
  65.     loadbank(config.cfg.currentBankDir);
  66.  
  67. };
  68.  
  69. Bank::~Bank(){
  70.     if (dirname!=NULL) {
  71.     sprintf(config.cfg.currentBankDir,"%s",dirname);
  72.     };
  73.     for (int i=0;i<MAX_NUM_BANKS;i++){
  74.     if (banks[i].dir!=NULL) delete (banks[i].dir);
  75.     if (banks[i].name!=NULL) delete (banks[i].name);
  76.     };
  77.  
  78.     clearbank();
  79. };
  80.  
  81. /*
  82.  * Get the name of an instrument from the bank
  83.  */
  84. char *Bank::getname (unsigned int ninstrument){
  85.     if (emptyslot(ninstrument)) return (defaultinsname);
  86.     return (ins[ninstrument].name);
  87. };
  88.  
  89. /*
  90.  * Get the numbered name of an instrument from the bank
  91.  */
  92. char *Bank::getnamenumbered (unsigned int ninstrument){
  93.     if (emptyslot(ninstrument)) return (defaultinsname);
  94.     snprintf(tmpinsname[ninstrument],PART_MAX_NAME_LEN+15,"%d. %s",ninstrument+1,getname(ninstrument));
  95.     return(tmpinsname[ninstrument]);
  96. };
  97.  
  98. /*
  99.  * Changes the name of an instrument (and the filename)
  100.  */
  101. void Bank::setname(unsigned int ninstrument,const char *newname,int newslot){
  102.     if (emptyslot(ninstrument)) return;
  103.     
  104.     char newfilename[1000+1],tmpfilename[100+1];
  105.     
  106.     ZERO(newfilename,1001);
  107.     ZERO(tmpfilename,101);
  108.     if (newslot>=0) snprintf(tmpfilename,100,"%4d-%s",newslot+1,newname);
  109.     else snprintf(tmpfilename,100,"%4d-%s",ninstrument+1,newname);
  110.     
  111.     //add the zeroes at the start of filename
  112.     for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0';
  113.  
  114.     //make the filenames legal
  115.     for (int i=0;i<(int) strlen(tmpfilename);i++) {
  116.     char c=tmpfilename[i];
  117.     if ((c>='0')&&(c<='9')) continue;
  118.     if ((c>='A')&&(c<='Z')) continue;
  119.     if ((c>='a')&&(c<='z')) continue;
  120.     if ((c=='-')||(c==' ')) continue;
  121.     
  122.     tmpfilename[i]='_';
  123.     };
  124.  
  125.     snprintf(newfilename,1000,"%s/%s.xiz",dirname,tmpfilename);
  126.  
  127. //    printf("rename %s -> %s\n",ins[ninstrument].filename,newfilename);//////////////
  128.  
  129.     rename(ins[ninstrument].filename,newfilename);
  130.     snprintf(ins[ninstrument].filename,1000,"%s",newfilename);
  131.     snprintf(ins[ninstrument].name,PART_MAX_NAME_LEN,"%s",&tmpfilename[5]);
  132.     
  133. };
  134.  
  135. /*
  136.  * Check if there is no instrument on a slot from the bank
  137.  */
  138. int Bank::emptyslot(unsigned int ninstrument){
  139.     if (ninstrument>=BANK_SIZE) return (1);
  140.     if (ins[ninstrument].filename==NULL) return(1);
  141.  
  142.     if (ins[ninstrument].used) return (0);
  143.     else return(1);
  144. };
  145.  
  146. /*
  147.  * Removes the instrument from the bank
  148.  */
  149. void Bank::clearslot(unsigned int ninstrument){
  150.     if (emptyslot(ninstrument)) return;
  151.     
  152. //    printf("remove  %s  \n",ins[ninstrument].filename);////////////////////////
  153.     
  154.     
  155.     remove(ins[ninstrument].filename);
  156.     deletefrombank(ninstrument);
  157. };
  158.  
  159. /*
  160.  * Save the instrument to a slot 
  161.  */
  162. void Bank::savetoslot(unsigned int ninstrument,Part *part){
  163.     clearslot(ninstrument);
  164.     
  165.     const int maxfilename=200;
  166.     char tmpfilename[maxfilename+20];
  167.     ZERO(tmpfilename,maxfilename+20);
  168.  
  169.     snprintf(tmpfilename,maxfilename,"%4d-%s",ninstrument+1,(char *)part->Pname);
  170.  
  171.     //add the zeroes at the start of filename
  172.     for (int i=0;i<4;i++) if (tmpfilename[i]==' ') tmpfilename[i]='0';
  173.     
  174.     //make the filenames legal
  175.     for (int i=0;i<(int)strlen(tmpfilename);i++) {
  176.     char c=tmpfilename[i];
  177.     if ((c>='0')&&(c<='9')) continue;
  178.     if ((c>='A')&&(c<='Z')) continue;
  179.     if ((c>='a')&&(c<='z')) continue;
  180.     if ((c=='-')||(c==' ')) continue;
  181.     
  182.     tmpfilename[i]='_';
  183.     };
  184.  
  185.     strncat(tmpfilename,".xiz",maxfilename+10);
  186.  
  187.     int fnsize=strlen(dirname)+strlen(tmpfilename)+10;
  188.     char *filename=new char[fnsize+4];
  189.     ZERO(filename,fnsize+2);
  190.  
  191.     snprintf(filename,fnsize,"%s/%s",dirname,tmpfilename);
  192.  
  193.     remove(filename);
  194.     part->saveXML(filename);
  195.     addtobank(ninstrument,tmpfilename,(char *) part->Pname);
  196.     
  197.     delete(filename);
  198. };
  199.  
  200. /*
  201.  * Loads the instrument from the bank
  202.  */
  203. void Bank::loadfromslot(unsigned int ninstrument,Part *part){
  204.     if (emptyslot(ninstrument)) return;
  205.     
  206.     part->defaultsinstrument();
  207.  
  208. //    printf("load:  %s\n",ins[ninstrument].filename);
  209.     
  210.     part->loadXMLinstrument(ins[ninstrument].filename);
  211.     
  212. };
  213.  
  214.  
  215. /*
  216.  * Load a bank from a file and makes it current
  217.  */
  218. int Bank::loadbank(const char *bankdirname){
  219.     DIR *dir=opendir(bankdirname);
  220.     clearbank();
  221.  
  222.     if (dir==NULL) return(-1);
  223.  
  224.     if (dirname!=NULL) delete(dirname);
  225.     dirname=new char[strlen(bankdirname)+1];
  226.     snprintf(dirname,strlen(bankdirname)+1,"%s",bankdirname);
  227.     bankfiletitle=dirname;
  228.  
  229.    // printf("loadbank %s/\n",bankdirname);
  230.     struct dirent *fn;
  231.         
  232.     while ((fn=readdir(dir))){
  233. #ifndef OS_WINDOWS
  234.     if (fn->d_type!=DT_REG) continue;
  235. #endif
  236.     const char *filename= fn->d_name;
  237.     
  238.     //sa verific daca e si extensia dorita
  239.     if (strstr(filename,INSTRUMENT_EXTENSION)==NULL) continue;
  240.     
  241.     //verify if the name is like this NNNN-name (where N is a digit)
  242.     int no=0;
  243.     unsigned int startname=0;
  244.     
  245.     for (unsigned int i=0;i<4;i++) {
  246.         if (strlen(filename)<=i) break;
  247.  
  248.         if ((filename[i]>='0')&&(filename[i]<='9')) {
  249.         no=no*10+(filename[i]-'0');
  250.         startname++;
  251.         };
  252.     };
  253.     
  254.     
  255.     if ((startname+1)<strlen(filename)) startname++;//to take out the "-"
  256.     
  257.     char name[PART_MAX_NAME_LEN+1]; 
  258.     ZERO(name,PART_MAX_NAME_LEN+1);
  259.     snprintf(name,PART_MAX_NAME_LEN,"%s",filename);
  260.     
  261.     //remove the file extension
  262.     for (int i=strlen(name)-1;i>=2;i--){
  263.         if (name[i]=='.') {
  264.         name[i]='\0';
  265.         break;
  266.         };
  267.     };
  268.     
  269.     if (no!=0){//the instrument position in the bank is found
  270.         addtobank(no-1,filename,&name[startname]);
  271.     } else {
  272.         addtobank(-1,filename,name);
  273.     };
  274.     
  275.     };
  276.     
  277.     
  278.     closedir(dir);
  279.     return(0);
  280. };
  281.  
  282. /*
  283.  * Makes a new bank, put it on a file and makes it current bank
  284.  */
  285. int Bank::newbank(const char *newbankdirname){
  286.     int result;
  287.     char tmpfilename[MAX_STRING_SIZE];
  288.     char bankdir[MAX_STRING_SIZE];
  289.     snprintf(bankdir,MAX_STRING_SIZE,"%s",config.cfg.bankRootDirList[0]);
  290.  
  291.     if (((bankdir[strlen(bankdir)-1])!='/')&&((bankdir[strlen(bankdir)-1])!='\\')){
  292.     strncat(bankdir,"/",MAX_STRING_SIZE);
  293.     };
  294.     strncat(bankdir,newbankdirname,MAX_STRING_SIZE);
  295. #ifdef OS_WINDOWS
  296.     result=mkdir(bankdir);
  297. #else
  298.     result=mkdir(bankdir,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  299. #endif
  300.     if (result<0) return(-1);
  301.  
  302.     snprintf(tmpfilename,MAX_STRING_SIZE,"%s/%s",bankdir,FORCE_BANK_DIR_FILE);
  303. //    printf("%s\n",tmpfilename);
  304.     FILE *tmpfile=fopen(tmpfilename,"w+");
  305.     fclose(tmpfile);
  306.     
  307.     return(loadbank(bankdir));
  308. };
  309.  
  310. /*
  311.  * Check if the bank is locked (i.e. the file opened was readonly)
  312.  */
  313. int Bank::locked(){
  314.     return(dirname==NULL);
  315. };
  316.  
  317. /*
  318.  * Swaps a slot with another
  319.  */
  320. void Bank::swapslot(unsigned int n1, unsigned int n2){
  321.     if ((n1==n2)||(locked())) return;
  322.     if (emptyslot(n1)&&(emptyslot(n2))) return;
  323.     if (emptyslot(n1)){//change n1 to n2 in order to make
  324.     int tmp=n2;n2=n1;n1=tmp;
  325.     };
  326.     
  327.     if (emptyslot(n2)){//this is just a movement from slot1 to slot2
  328.     setname(n1,getname(n1),n2);
  329.     ins[n2]=ins[n1];
  330.     ins[n1].used=false;
  331.     ins[n1].name[0]='\0';
  332.     ins[n1].filename=NULL;
  333.     ins[n1].info.PADsynth_used=0;
  334.     } else {//if both slots are used
  335.     if (strcmp(ins[n1].name,ins[n2].name)==0){//change the name of the second instrument if the name are equal
  336.         strncat(ins[n2].name,"2",PART_MAX_NAME_LEN);
  337.     };
  338.     setname(n1,getname(n1),n2);
  339.     setname(n2,getname(n2),n1);
  340.     ins_t tmp;
  341.     tmp.used=true;
  342.     strcpy(tmp.name,ins[n2].name);
  343.     char *tmpfilename=ins[n2].filename;
  344.     bool padsynth_used=ins[n2].info.PADsynth_used;
  345.     
  346.     ins[n2]=ins[n1];
  347.     strcpy(ins[n1].name,tmp.name);
  348.     ins[n1].filename=tmpfilename;
  349.     ins[n1].info.PADsynth_used=padsynth_used;
  350.     };
  351.     
  352. };
  353.  
  354.  
  355. //a helper function that compares 2 banks[] arrays
  356. int Bank_compar(const void *a,const void *b){
  357.     struct Bank::bankstruct *bank1= (Bank::bankstruct *)a;
  358.     struct Bank::bankstruct *bank2= (Bank::bankstruct *)b;
  359.     if (((bank1->name)==NULL)||((bank2->name)==NULL)) return(0);
  360.     
  361.     return(strcasecmp(bank1->name,bank2->name));
  362. };
  363.  
  364. /*
  365.  * Re-scan for directories containing instrument banks
  366.  */
  367.  
  368. void Bank::rescanforbanks(){
  369.  
  370.     for (int i=0;i<MAX_NUM_BANKS;i++){
  371.     if (banks[i].dir!=NULL) delete (banks[i].dir);
  372.     if (banks[i].name!=NULL) delete (banks[i].name);
  373.     banks[i].dir=NULL;
  374.     banks[i].name=NULL;
  375.     };
  376.  
  377.     for (int i=0;i<MAX_BANK_ROOT_DIRS;i++) if (config.cfg.bankRootDirList[i]!=NULL) scanrootdir(config.cfg.bankRootDirList[i]);
  378.     
  379.     qsort(banks,MAX_NUM_BANKS,sizeof(bankstruct),Bank_compar);
  380. }; 
  381.  
  382.  
  383.  
  384. // private stuff
  385.  
  386. void Bank::scanrootdir(char *rootdir){
  387. //    printf("Scanning root dir:%s\n",rootdir);
  388.     DIR *dir=opendir(rootdir);
  389.     if (dir==NULL) return;
  390.  
  391.     const int maxdirsize=1000;
  392.     struct {
  393.     char dir[maxdirsize];
  394.     char name[maxdirsize];    
  395.     }bank;
  396.  
  397.     char *separator="/";
  398.     if (strlen(rootdir)) {
  399.     char tmp=rootdir[strlen(rootdir)-1];
  400.     if ((tmp=='/') || (tmp=='\\')) separator="";
  401.     };
  402.     
  403.     struct dirent *fn;
  404.     while ((fn=readdir(dir))){
  405. #ifndef OS_WINDOWS
  406.     if (fn->d_type!=DT_DIR) continue;//this is not a directory
  407. #endif
  408.     const char *dirname=fn->d_name;
  409.     if (dirname[0]=='.') continue;
  410.     
  411.     snprintf(bank.dir,maxdirsize,"%s%s%s/",rootdir,separator,dirname);
  412.     snprintf(bank.name,maxdirsize,"%s",dirname);
  413.     //find out if the directory contains at least 1 instrument
  414.     bool isbank=false;
  415.     
  416.     DIR *d=opendir(bank.dir);
  417.     if (d==NULL) continue;
  418.     
  419.     struct dirent *fname;
  420.  
  421.     while((fname=readdir(d))){
  422. #ifndef OS_WINDOWS
  423.         if (fname->d_type!=DT_REG) continue;//this is not a regular file
  424. #endif
  425.         if ((strstr(fname->d_name,INSTRUMENT_EXTENSION)!=NULL)||
  426.            (strstr(fname->d_name,FORCE_BANK_DIR_FILE)!=NULL)){
  427.         isbank=true;
  428.         break;//aici as putea pune in loc de break un update la un counter care imi arata nr. de instrumente din bank
  429.         };
  430.     };
  431.     
  432.     closedir(d);    
  433.     
  434.     if (isbank) {
  435.         int pos=-1;
  436.         for (int i=1;i<MAX_NUM_BANKS;i++){    //banks[0] e liber intotdeauna
  437.         if (banks[i].name==NULL) {
  438.             pos=i;
  439.             break;
  440.         };
  441.         };
  442.         
  443.         if (pos>=0) {
  444.         banks[pos].name=new char[maxdirsize];
  445.         banks[pos].dir=new char[maxdirsize];
  446.             snprintf(banks[pos].name,maxdirsize,"%s",bank.name);
  447.             snprintf(banks[pos].dir,maxdirsize,"%s",bank.dir);
  448.         };
  449.         
  450.     };
  451.     
  452.     };
  453.  
  454.     closedir(dir);
  455.     
  456. };
  457.  
  458. void Bank::clearbank(){
  459.     for (int i=0;i<BANK_SIZE;i++) deletefrombank(i);
  460.     if (dirname!=NULL) delete(dirname);
  461.     bankfiletitle=NULL;
  462.     dirname=NULL;
  463. };
  464.  
  465. int Bank::addtobank(int pos, const char *filename, const char* name){
  466.     if ((pos>=0)&&(pos<BANK_SIZE)){
  467.     if (ins[pos].used) pos=-1;//force it to find a new free position
  468.     } else if (pos>=BANK_SIZE) pos=-1;
  469.     
  470.     
  471.     if (pos<0) {//find a free position
  472.     for (int i=BANK_SIZE-1;i>=0;i--)
  473.         if (!ins[i].used) {
  474.         pos=i;
  475.         break;
  476.         };
  477.     
  478.     };
  479.     
  480.     if (pos<0) return (-1);//the bank is full
  481.  
  482.    // printf("%s   %d\n",filename,pos);
  483.  
  484.     deletefrombank(pos);
  485.     
  486.     ins[pos].used=true;
  487.     snprintf(ins[pos].name,PART_MAX_NAME_LEN,"%s",name);
  488.  
  489.     snprintf(tmpinsname[pos],PART_MAX_NAME_LEN+10," ");
  490.  
  491.     int len=strlen(filename)+1+strlen(dirname);
  492.     ins[pos].filename=new char[len+1];
  493.     snprintf(ins[pos].filename,len+1,"%s/%s",dirname,filename);
  494.  
  495.     //see if PADsynth is used
  496.     if (config.cfg.CheckPADsynth){
  497.     XMLwrapper *xml=new XMLwrapper();
  498.     xml->checkfileinformation(ins[pos].filename);
  499.     
  500.     ins[pos].info.PADsynth_used=xml->information.PADsynth_used;
  501.     delete(xml);
  502.     } else ins[pos].info.PADsynth_used=false;
  503.     
  504.     return(0);
  505. };
  506.  
  507. bool Bank::isPADsynth_used(unsigned int ninstrument){
  508.     if (config.cfg.CheckPADsynth==0) return(0);
  509.     else return(ins[ninstrument].info.PADsynth_used);
  510. };
  511.  
  512.  
  513. void Bank::deletefrombank(int pos){
  514.     if ((pos<0)||(pos>=BANK_SIZE)) return;
  515.     ins[pos].used=false;
  516.     ZERO(ins[pos].name,PART_MAX_NAME_LEN+1);
  517.     if (ins[pos].filename!=NULL) {
  518.     delete (ins[pos].filename);
  519.     ins[pos].filename=NULL;
  520.     };
  521.     
  522.     ZERO(tmpinsname[pos],PART_MAX_NAME_LEN+20);
  523.     
  524. };
  525.  
  526.