|
- /*
- ==============================================================================
-
- This file is part of the JUCETICE project - Copyright 2009 by Lucio Asnaghi.
-
- JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2007 by Julian Storer.
-
- ------------------------------------------------------------------------------
-
- JUCE and JUCETICE can be redistributed and/or modified 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.
-
- JUCE and JUCETICE are distributed in the hope that they 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 JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ==============================================================================
- */
-
- BEGIN_JUCE_NAMESPACE
-
- //==============================================================================
- enum TuningMapSection
- {
- SEC_None = 0,
- SEC_Unknown = 1,
- SEC_Tuning = 2,
- SEC_ExactTuning = 3
- };
-
- extern const String g_equal_tuning;
-
-
- //==============================================================================
- TuningMap::TuningMap()
- {
- reset(); // Provide a standard tuning
-
- MemoryInputStream mis((const char*)g_equal_tuning.toUTF8(), g_equal_tuning.length(), false);
-
- readFromStream(mis);
- }
-
- TuningMap::~TuningMap()
- {
- }
-
- //==============================================================================
- void TuningMap::reset()
- {
- m_dblBaseFreq = 8.1757989156437073336; // Means A = 440Hz
- for ( int i = 0 ; i < 128 ; ++i )
- m_dblTunes[i] = 100 * i;
- }
-
-
- //==============================================================================
- bool TuningMap::writeToStream (OutputStream& ofs, bool bSaveBaseFreq)
- {
- int i;
- char endl = '\n';
-
- ofs << ";" << endl;
- ofs << "; AnaMark / VAZ 1.5 Plus-compatible tuning map file" << endl;
- ofs << ";" << endl;
- ofs << ";" << endl;
- ofs << "; 1. VAZ-section with quantized tunings" << endl;
- ofs << ";" << endl;
-
- ofs << "[Tuning]" << endl;
- for ( i = 0 ; i < 128 ; ++i )
- ofs << "note " << i << "=" << (int)(m_dblTunes[i]) << endl;
-
- ofs << ";" << endl;
- ofs << "; 2. AnaMark-specific section with exact tunings" << endl;
- ofs << ";" << endl;
- ofs << "[Exact Tuning]" << endl;
- // ofs.precision(10);
- if ( bSaveBaseFreq )
- ofs << "basefreq = " << m_dblBaseFreq << endl;
- for ( i = 0 ; i < 128 ; ++i )
- ofs << "note " << i << "=" << m_dblTunes[i] << endl;
-
- // Always returns true, because currently there's no error processing
- return true;
- }
-
-
- //==============================================================================
- bool TuningMap::readFromStream (InputStream& ifs)
- {
- char szLine[512];
- long lTunes[128]; // For temporary use, unit: Cents
- bool bTuningFound = false;
- bool bExactTuningFound = false;
- long lET_LastNoteFound = -1;
- long lLineCount = 0;
- TuningMapSection secCurr = SEC_None;
-
- // Initialize data
- // Important, because notes not listed in the tuning file
- // should always have standard tuning.
- reset();
- for ( int i = 0 ; i < 128 ; ++i )
- lTunes[i] = (long)m_dblTunes[i];
-
- while ( !ifs.isExhausted() )
- {
- // Increase Line counter to make it easier detecting errors, if
- // a more detailed output is wanted.
- ++lLineCount;
-
- // Read line, until '\n', '\r' or '\0' is reached
- // Thus it is able to read WIN/DOS-style as well as UNIX-style files
- // By the way: Skip empty lines or multiple line-end-characters
- // Is not case sensitive, so all chars are converted to lower ones
- int nCurrPos = 0;
- do
- {
- while ( (!ifs.isExhausted()) && (nCurrPos < 510) )
- {
- char ch = '\0';
- ifs.read(&ch, 1);
- if ( (ch == '\0') || (ch == '\r') || (ch == '\n') )
- break;
- szLine[nCurrPos++] = (char) tolower(ch);
- }
- } while ( (!ifs.isExhausted()) && (nCurrPos == 0) );
- if ( nCurrPos >= 510 )
- {
- // xTRACE( "Line too long - line " << lLineCount );
- return false; // Line too long
- }
- szLine[nCurrPos] = '\0';
-
- // Skip leading spaces/tabs
- const char * szCurr = szLine;
- while ( (*szCurr != '\0') && ((*szCurr == ' ') || (*szCurr == '\t')) )
- ++szCurr;
-
- // Skip empty lines
- if ( szCurr[0] == '\0' )
- continue;
-
- // Skip comment lines
- if ( szCurr[0] == ';' )
- continue;
-
- // Skip trailing spaces/tabs
- char * szLast = (char *) &szCurr[strlen(szCurr)-1];
- while ( (szLast > szCurr) && ((*szLast == ' ') || (*szLast == '\t')) )
- --szLast;
- *(szLast+1) = '\0';
-
- // Check for new section
- if ( szCurr[0] == '[' )
- {
- if ( szCurr[strlen(szCurr)-1] != ']' )
- {
- // xTRACE( "Syntax error: Section-tag must be the only string in the line! - line " << lLineCount );
- return false; // error in section-tag! Must be the only one string in the line!
- }
- // Known section found?
- secCurr = SEC_Unknown;
- if ( strcmp(&szCurr[1], "tuning]") == 0 )
- {
- secCurr = SEC_Tuning;
- bTuningFound = true;
- }
- if ( strcmp(&szCurr[1], "exact tuning]") == 0 )
- {
- secCurr = SEC_ExactTuning;
- bExactTuningFound = true;
- }
- // Now process next line
- continue;
- }
-
- // Skip all lines which are in none or in an unknown section
- if ( (secCurr == SEC_None) || (secCurr == SEC_Unknown) )
- continue;
-
- // Separate parameter name and value
- const char * szParam = szCurr;
- const char * szValue = strchr(szCurr, '=');
- if ( szValue == 0 )
- {
- // xTRACE( "Syntax error: '=' missing! - line " << lLineCount );
- return false; // definitely an error: '=' missing!
- }
- ++szValue; // Set the pointer to the first char behind the '='
- // Now skip trailing spaces/tabs of parameter name:
- szLast = (char *) &szValue[-2];
- while ( (szLast > szParam) && ((*szLast == ' ') || (*szLast == '\t')) )
- --szLast;
- *(szLast+1) = '\0';
- // Now skip leading spaces/tabs of value:
- while ( (*szValue != '\0') && ((*szValue == ' ') || (*szValue == '\t')) )
- ++szValue;
-
- // Now process the different sections:
- switch ( secCurr )
- {
- case SEC_Tuning:
- {
- // Check for note-tag
- if ( memcmp(szParam, "note", 4) != 0 )
- continue; // note-tag not found, ignore line in case that it's
- // an option of a later version
- // If you want, you can return here false and process it as an error
-
- // Get MIDI-Note number
- int lNoteIndex = atol(&szParam[4]);
- // Check for correct range [0;127] and ignore it, if it's out
- // of range.
- if ( (lNoteIndex < 0) || (lNoteIndex > 127) )
- continue;
- lTunes[lNoteIndex] = atol(szValue);
- }
- break;
-
- case SEC_ExactTuning:
- {
- // Check for note-tag
- if ( memcmp(szParam, "note", 4) == 0 )
- {
- // note-tag found
- // Get MIDI-Note number
- int lNoteIndex = atol(&szParam[4]);
- // Check for correct range [0;127] and ignore it, if it's out
- // of range.
- if ( (lNoteIndex < 0) || (lNoteIndex > 127) )
- continue;
- m_dblTunes[lNoteIndex] = atof(szValue);
- if ( lET_LastNoteFound < lNoteIndex )
- lET_LastNoteFound = lNoteIndex;
- // O.K. -> Process next line
- continue;
- }
- // Check for basefreq parameter
- if ( strcmp(szParam, "basefreq") == 0 )
- {
- // basefreq found
- m_dblBaseFreq = atof(szValue);
- // O.K. -> Process next line
- continue;
- }
- // No known parameter found, so skip it
- continue;
- }
- break;
-
- default: // This part of the code should never be reached!
- // assert(false);
- // xTRACE( "Compilation error! Section not coded! - line " << lLineCount );
- return false;
- }
- }
-
- if ( (!bTuningFound) && (!bExactTuningFound) )
- {
- // xTRACE( "No tuning data found!" );
- return false; // No tuning data found at all should be worth an error...
- }
-
- if ( !bExactTuningFound )
- {
- // There are no exact tuning values, so map the quantized
- // values to the exact ones:
- for ( int i = 0 ; i < 128 ; ++i )
- m_dblTunes[i] = (double) lTunes[i];
- }
- else
- {
- // [Exact Tuning] section found, so ignore the values found
- // in the [Tuning] section and do the "auto expand":
- if ( (lET_LastNoteFound >= 0) && (lET_LastNoteFound < 127) )
- {
- // Now loop the given data (auto expand):
- int H = lET_LastNoteFound; // Highest MIDI note number
- double P = m_dblTunes[H]; // Period length
- for ( int i = H ; i < 128 ; ++i )
- m_dblTunes[i] = m_dblTunes[i-H] + P;
- }
- }
-
- return true; // Everything nice!
- }
-
- //==============================================================================
- bool TuningMap::setBaseFreq (double dblBaseFreq)
- {
- // jassert( dblBaseFreq > 0 );
-
- // First make sure, that the base frequency is in the valid range
- if ( dblBaseFreq > 0 )
- {
- m_dblBaseFreq = dblBaseFreq;
- return true;
- }
- else
- {
- return false;
- }
- }
-
- bool TuningMap::setRelativeTune (int nNoteIndex, double dblTune)
- {
- // jassert( (nNoteIndex >= 0) && (nNoteIndex <= 127) );
-
- // First make sure, that the note index is in the valid range
- if ( (nNoteIndex >= 0) && (nNoteIndex <= 127) )
- {
- m_dblTunes[nNoteIndex] = dblTune;
- return true;
- }
- else
- {
- return false;
- }
- }
-
- //==============================================================================
- const String g_equal_tuning =
- "; VAZ Plus 1.5 tuning map file \
- ; Equal Temperament\
- [Tuning]\
- note 0=0\
- note 1=100\
- note 2=200\
- note 3=300\
- note 4=400\
- note 5=500\
- note 6=600\
- note 7=700\
- note 8=800\
- note 9=900\
- note 10=1000\
- note 11=1100\
- note 12=1200\
- note 13=1300\
- note 14=1400\
- note 15=1500\
- note 16=1600\
- note 17=1700\
- note 18=1800\
- note 19=1900\
- note 20=2000\
- note 21=2100\
- note 22=2200\
- note 23=2300\
- note 24=2400\
- note 25=2500\
- note 26=2600\
- note 27=2700\
- note 28=2800\
- note 29=2900\
- note 30=3000\
- note 31=3100\
- note 32=3200\
- note 33=3300\
- note 34=3400\
- note 35=3500\
- note 36=3600\
- note 37=3700\
- note 38=3800\
- note 39=3900\
- note 40=4000\
- note 41=4100\
- note 42=4200\
- note 43=4300\
- note 44=4400\
- note 45=4500\
- note 46=4600\
- note 47=4700\
- note 48=4800\
- note 49=4900\
- note 50=5000\
- note 51=5100\
- note 52=5200\
- note 53=5300\
- note 54=5400\
- note 55=5500\
- note 56=5600\
- note 57=5700\
- note 58=5800\
- note 59=5900\
- note 60=6000\
- note 61=6100\
- note 62=6200\
- note 63=6300\
- note 64=6400\
- note 65=6500\
- note 66=6600\
- note 67=6700\
- note 68=6800\
- note 69=6900\
- note 70=7000\
- note 71=7100\
- note 72=7200\
- note 73=7300\
- note 74=7400\
- note 75=7500\
- note 76=7600\
- note 77=7700\
- note 78=7800\
- note 79=7900\
- note 80=8000\
- note 81=8100\
- note 82=8200\
- note 83=8300\
- note 84=8400\
- note 85=8500\
- note 86=8600\
- note 87=8700\
- note 88=8800\
- note 89=8900\
- note 90=9000\
- note 91=9100\
- note 92=9200\
- note 93=9300\
- note 94=9400\
- note 95=9500\
- note 96=9600\
- note 97=9700\
- note 98=9800\
- note 99=9900\
- note 100=10000\
- note 101=10100\
- note 102=10200\
- note 103=10300\
- note 104=10400\
- note 105=10500\
- note 106=10600\
- note 107=10700\
- note 108=10800\
- note 109=10900\
- note 110=11000\
- note 111=11100\
- note 112=11200\
- note 113=11300\
- note 114=11400\
- note 115=11500\
- note 116=11600\
- note 117=11700\
- note 118=11800\
- note 119=11900\
- note 120=12000\
- note 121=12100\
- note 122=12200\
- note 123=12300\
- note 124=12400\
- note 125=12500\
- note 126=12600\
- note 127=12700\
- ";
-
- END_JUCE_NAMESPACE
-
|