1
// RCS-ID: $Id: AuxString.cpp,v 1.10 2006/02/28 17:39:56 cecilios Exp $
2
//--------------------------------------------------------------------------------------
3
// LenMus Phonascus: The teacher of music
4
// Copyright (c) 2002-2006 Cecilio Salmeron
6
// This program is free software; you can redistribute it and/or modify it under the
7
// terms of the GNU General Public License as published by the Free Software Foundation;
8
// either version 2 of the License, or (at your option) any later version.
10
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12
// PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License along with this
15
// program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
16
// Fifth Floor, Boston, MA 02110-1301, USA.
18
// For any comment, suggestion or feature request, please contact the manager of
19
// the project at cecilios@users.sourceforge.net
21
//-------------------------------------------------------------------------------------
22
/*! @file AuxString.cpp
23
@brief Implementation file for auxiliary global functions to verify / convert strings
27
// #pragma implementation
30
// for (compilers that support precompilation, includes "wx/wx.h".
31
#include "wx/wxprec.h"
41
#include "../score/score.h"
42
#include "AuxString.h"
43
#include "../auxmusic/Conversion.h"
45
//----------------------------------------------------------------------------------------
46
/*! @page note_names lmNote names and pitch values
49
nPitchMIDI: chromatic pitch: number representing the note in a chromatic scale. It is
50
the same as the number used in MIDI for representing pitch.
51
nPitch: diatonic pitch: number representing the note in a diatonic scale
52
nOctave: octave number (as MIDI). The lowest scale (-1) is not yet used
54
a pitch value of 0 (zero) represents a rest.
57
name Octave PitchMIDI Pitch Observations
58
---- ------ --------- ------- -----------------------------------
61
c0 0 12 1 Do2 de la subcontraoctava (16,35 Hz)
68
c1 1 24 8 Do1 de la contraoctava
69
c2 2 36 15 Do de la gran octava
70
c3 3 48 22 do de la peque�a octava
71
c4 4 60 29 do1 de la octava primera (la1 = 440Hz)
76
c5 5 72 36 do2 de la octava segunda
77
c6 6 84 43 do3 de la octava tercera
78
c7 7 96 50 do4 de la octava cuarta
79
c8 8 108 57 do5 de la octava quinta (4.186 Hz)
82
Accidentals are represented by minus (-) and plus (+) signs before the note name
90
i.e.: ++c3, =+c3, +c3, =c3, -c3, --c3, =-c3
92
Pitch name can also be a number, representing MIDI pitch. i.e.: (n 29 n) = (n c4 n)
95
//-------------------------------------------------------------------------------------------*/
97
/*! @brief Convert LDP pitch name to pitch and accidentals
99
Convert LDP pitch name to pitch and accidentals.
100
@return Returns true if error (sPitch is not a valid pitch name)
101
Otherwise, stores the corresponding data into the parameters pPitch, and
104
@param[in] sPitch The LDP string with the pitch to convert. Pitch is represented
105
as the combination of the chromatic alteration, the step in the
106
diatonic scale, and the octave (i.e. "+c4").
107
@param[out] pPitch Diatonic MIDI pitch.
108
@param[out] pAccidentals parameter represents chromatic accidentals (does not
109
include key signature accidentals)
111
bool PitchNameToData(wxString sPitch, int* pPitch, EAccidentals* pAccidentals)
114
//It is assumed that sPitch is Trimed (no spaces before or after real data) and lower case
117
//if sPitch is a number it is interpreted as a MIDI pitch
118
if (sPitch.IsNumber()) {
120
fError = !sPitch.ToLong(&nAux);
123
*pAccidentals = eNoAccidentals;
125
analizar la nota MIDI y determinar las
126
alteraciones en funci�n de la armadura
131
//sPitch is alfanumeric: must be letter followed by a number (i.e.: "c4" )
134
//split the string: accidentals and name
135
switch (sPitch.Len()) {
140
sAlter = sPitch.Mid(0, 1);
141
sPitch = sPitch.Mid(1, 2);
144
sAlter = sPitch.Mid(0, 2);
145
sPitch = sPitch.Mid(2, 2);
151
wxString sStep = sPitch.Left(1);
152
wxString sOctave = sPitch.Mid(1, 1);
153
fError = StringToPitch(sStep, sOctave, pPitch);
154
if (fError) return true;
156
//analyse accidentals
157
if (sAlter.IsEmpty()) {
158
*pAccidentals = eNoAccidentals;
159
} else if (sAlter.StartsWith( _T("+") )) {
160
if (sAlter.StartsWith( _T("++") )) {
161
*pAccidentals = eDoubleSharp;
163
*pAccidentals = eSharp;
165
} else if (sAlter.StartsWith( _T("-") )) {
166
if (sAlter.StartsWith( _T("--") )) {
167
*pAccidentals = eFlatFlat;
169
*pAccidentals = eFlat;
171
} else if (sAlter.StartsWith( _T("=+") )) {
172
*pAccidentals = eNaturalSharp;
173
} else if (sAlter.StartsWith( _T("=-") )) {
174
*pAccidentals = eNaturalFlat;
175
} else if (sAlter.StartsWith( _T("=") )) {
176
*pAccidentals = eNatural;
181
return false; //no error
185
bool StringToPitch(wxString sStep, wxString sOctave, int* pPitch)
188
sStep is a one char string: "a" to "g", in lower case
189
sOctave is a one char string: "0" to "9"
191
returns true if error (sStep is not "a"-"g" or sOctave not "0"-"9")
192
Otherwise, stores the corresponding data into the parameters nPitch.
196
//analyze the letter and store it as diatonic pitch step
197
*pPitch = LetterToStep(sStep) + 1;
198
if (*pPitch == 0) return true; //error
200
//combine octave with pitch step
201
if (! sOctave.IsNumber()) {
206
bool fError = !sOctave.ToLong(&nOctave);
208
*pPitch = *pPitch + 7 * nOctave;
210
return (nOctave < 0 || nOctave > 9); //true if error
214
//---------------------------------------------------------------------------------------------
215
// Receives a string (sNoteType) with the LDP letter for the type of note and, optionally,
217
// Set up variables nNoteType and flags fDotted and fDoubleDotted.
219
// USA UK ESP LDP NoteType
220
// ----------- -------------------- ------------- --- ---------
221
// Long Breve cuadrada d eLong = 0
222
// Whole Semibreve redonda r eWhole = 1
223
// half minim blanca b eHalf = 2
224
// quarter crochet negra n eQuarter = 3
225
// eighth quaver corchea c eEighth = 4
226
// sixteenth semiquaver semicorchea s e16th = 5
227
// 32th demisemiquaver fusa f e32th = 6
228
// 64th hemidemisemiquaver semifusa m e64th = 7
229
// 128th garrapatea g e128th = 8
230
// 256th semigarrapatea p e256th = 9
232
// Returns true if error in parsing
233
//---------------------------------------------------------------------------------------------
234
bool NoteTypeToData(wxString sNoteType, ENoteType* pnNoteType, bool* pfDotted, bool* pfDoubleDotted)
236
sNoteType.Trim(false); //remove spaces from left
237
sNoteType.Trim(true); //and from the right
239
switch (sNoteType.GetChar(0)) {
244
*pnNoteType = eWhole;
250
*pnNoteType = eQuarter;
253
*pnNoteType = eEighth;
265
*pnNoteType = e128th;
268
*pnNoteType = e256th;
276
*pfDoubleDotted = false;
277
if (sNoteType.Len() > 1) {
278
sNoteType = sNoteType.Mid(1);
279
if (sNoteType.StartsWith( _T("..") )) {
280
*pfDoubleDotted = true;
281
} else if (sNoteType.StartsWith( _T(".") )) {
288
return false; //no error
292
int LetterToStep(wxString sStep)
294
//analyze the letter and return it as diatonic note number
295
wxChar cStep = sStep.GetChar(0);
317
//! Receives an pattern (a group of elements) and returns its duration
318
float SrcGetPatternDuracion(wxString sPattern)
321
split the segment into elements, coumpute the duration of
322
each element and return the total duration of the segment
326
float rPatternDuration=0.0;
328
wxString sSource = sPattern;
329
while (sSource != _T("") )
331
//extract the element and remove it from source
332
iEnd = SrcSplitPattern(sSource) + 1;
333
sElement = sSource.Mid(0, iEnd);
334
sSource = sSource.Mid(iEnd);
336
//compute element's duration
337
rPatternDuration += SrcGetElementDuracion(sElement);
339
return rPatternDuration;
343
//! Receives an element (note or rest) and returns its duration
344
float SrcGetElementDuracion(wxString sElement)
346
//element is either (n ppp ddd ...) or (s ddd ...). We need the ddd
350
wxString sElementType = sElement.Mid(1, 1);
351
if (sElementType == _T("n") ) {
353
sAux = sElement.Mid(3);
354
} else if (sElementType == _T("s") ) {
359
iStart = sAux.Find(_T(" ")) + 1;
363
while (sAux.Mid(i, 1) == _T(".") ) i++;
365
//extract NoteType and dots
366
wxString sNoteType = sAux.Mid(iStart, i - iStart);
369
return LDPNoteTypeToDuration(sNoteType);
373
/*! returns true if received element is a rest
374
sElement must be normalized (lower case, no extra spaces)
376
bool SrcIsRest(wxString sElement)
378
return (sElement.Mid(1, 1) == _T("s") );
381
/*! Receives an string formed by concatenated elements, for example:
382
"(n * n)(n * s g+)(n * s)(n * c g-)"
383
sSource must be normalized (lower case, no extra spaces)
384
@return the index to the end (closing parenthesis) of first element
386
int SrcSplitPattern(wxString sSource)
388
int i; //index to character being explored
389
int iMax; //sSource length
390
int nAPar; //open parenthesis counter
392
iMax = sSource.Length();
393
wxASSERT(iMax > 0); //sSource must not be empty
394
wxASSERT(sSource.Mid(0, 1) == _T("(") ); //must start with parenthesis
396
nAPar = 1; //let//s count first parenthesis
397
//look for the matching closing parenthesis
399
for (i=1; i < iMax; i++) {
400
if (sSource.Mid(i, 1) == _T("(") ) {
402
} else if (sSource.Mid(i, 1) == _T(")") ) {
405
//matching parenthesis found. Exit loop
418
//----------------------------------------------------------------------------------------
420
//----------------------------------------------------------------------------------------
423
bool LDPDataToPitch(wxString sPitch, EAccidentals* pAccidentals,
424
wxString* sStep, wxString* sOctave)
427
Analyzes string sPitch (LDP format) and extracts its parts (Step, octave and
428
accidentals) and stores them in the corresponding parameters.
429
Returns true if error (sPitch is not a valid pitch name)
431
In LDP pitch is represented as a combination of the step of the diatonic scale, the
432
chromatic alteration, and the octave.
433
- The nAccidentals parameter represents chromatic alteration (does not include tonal
435
- The octave element is represented by the numbers 0 to 9, where 4 indicates
436
the octave started by middle C.
439
//It is assumed that sPitch is Trimed (no spaces before or after real data) and lower case
442
//if sPitch is a number it is interpreted as a MIDI pitch
443
if (sPitch.IsNumber()) {
445
fError = !sPitch.ToLong(&nAux);
447
lmConverter oConverter;
448
sPitch = oConverter.MidiPitchToLDPName((lmPitch) nAux);
449
nAux = sPitch.Length();
451
*sStep = sPitch.Mid(0, 1);
452
*sOctave = sPitch.Mid(1);
453
*pAccidentals = eNoAccidentals;
456
*sStep = sPitch.Mid(1, 1);
457
*sOctave = sPitch.Mid(2);
458
*pAccidentals = eSharp;
463
//sPitch is alfanumeric: must be letter followed by a number (i.e.: "c4" )
466
//split the string: accidentals and name
467
switch (sPitch.Len()) {
472
sAlter = sPitch.Mid(0, 1);
473
sPitch = sPitch.Mid(1, 2);
476
sAlter = sPitch.Mid(0, 2);
477
sPitch = sPitch.Mid(2, 2);
483
*sStep = sPitch.Left(1);
484
*sOctave = sPitch.Mid(1, 1);
486
//analyse accidentals
487
if (sAlter.IsEmpty()) {
488
*pAccidentals = eNoAccidentals;
489
} else if (sAlter.StartsWith( _T("+") )) {
490
if (sAlter.StartsWith( _T("++") )) {
491
*pAccidentals = eDoubleSharp;
493
*pAccidentals = eSharp;
495
} else if (sAlter.StartsWith( _T("-") )) {
496
if (sAlter.StartsWith( _T("--") )) {
497
*pAccidentals = eFlatFlat;
499
*pAccidentals = eFlat;
501
} else if (sAlter.StartsWith( _T("=+") )) {
502
*pAccidentals = eNaturalSharp;
503
} else if (sAlter.StartsWith( _T("=-") )) {
504
*pAccidentals = eNaturalFlat;
505
} else if (sAlter.StartsWith( _T("=") )) {
506
*pAccidentals = eNatural;
511
return false; //no error
515
/// Returns -1 if error
516
EClefType LDPNameToClef(wxString sClefName)
518
EClefType nClef = eclvSol;
519
if (sClefName == _T("Do1")) {
521
} else if (sClefName == _T("Do2")) {
523
} else if (sClefName == _T("Do3")) {
525
} else if (sClefName == _T("Do4")) {
527
} else if (sClefName == _T("Sol")) {
529
} else if (sClefName == _T("Fa3")) {
531
} else if (sClefName == _T("Fa4")) {
533
} else if (sClefName == _T("SinClave")) {
536
return (EClefType)-1;
540
EKeySignatures LDPNameToKey(wxString sKeyName)
542
static wxString m_sLDPKeyNames[lmMAX_KEY - lmMIN_KEY + 1];
543
static bool m_fLDPNamesLoaded = false;
545
if (!m_fLDPNamesLoaded) {
546
//major key signatures
547
m_sLDPKeyNames[earmDo] = _T("Do");
548
m_sLDPKeyNames[earmSol] = _T("Sol");
549
m_sLDPKeyNames[earmRe] = _T("Re");
550
m_sLDPKeyNames[earmLa] = _T("La");
551
m_sLDPKeyNames[earmMi] = _T("Mi");
552
m_sLDPKeyNames[earmSi] = _T("Si");
553
m_sLDPKeyNames[earmFas] = _T("Fa#");
554
m_sLDPKeyNames[earmDos] = _T("Do#");
555
m_sLDPKeyNames[earmDob] = _T("Dob");
556
m_sLDPKeyNames[earmSolb] = _T("Solb");
557
m_sLDPKeyNames[earmReb] = _T("Reb");
558
m_sLDPKeyNames[earmLab] = _T("Lab");
559
m_sLDPKeyNames[earmMib] = _T("Mib");
560
m_sLDPKeyNames[earmSib] = _T("Sib");
561
m_sLDPKeyNames[earmFa] = _T("Fa");
562
// minor key signatures
563
m_sLDPKeyNames[earmLam] = _T("Lam");
564
m_sLDPKeyNames[earmMim] = _T("Mim");
565
m_sLDPKeyNames[earmSim] = _T("Sim");
566
m_sLDPKeyNames[earmFasm] = _T("Fa#m");
567
m_sLDPKeyNames[earmDosm] = _T("Do#m");
568
m_sLDPKeyNames[earmSolsm] = _T("Sol#m");
569
m_sLDPKeyNames[earmResm] = _T("Re#m");
570
m_sLDPKeyNames[earmLasm] = _T("La#m");
571
m_sLDPKeyNames[earmLabm] = _T("Labm");
572
m_sLDPKeyNames[earmMibm] = _T("Mibm");
573
m_sLDPKeyNames[earmSibm] = _T("Sibm");
574
m_sLDPKeyNames[earmFam] = _T("Fam");
575
m_sLDPKeyNames[earmDom] = _T("Dom");
576
m_sLDPKeyNames[earmSolm] = _T("Solm");
577
m_sLDPKeyNames[earmRem] = _T("Rem");
578
m_fLDPNamesLoaded = true;
582
for (i = lmMIN_KEY; i <= lmMAX_KEY; i++) {
583
if (m_sLDPKeyNames[i-lmMIN_KEY] == sKeyName) return (EKeySignatures)i;
585
return (EKeySignatures)-1;
591
//----------------------------------------------------------------------------------------
593
//----------------------------------------------------------------------------------------
595
bool XmlDataToClef(wxString sClefLine, EClefType* pClef)
597
if (sClefLine == _T("C1")) {
599
} else if (sClefLine == _T("C2")) {
601
} else if (sClefLine == _T("C3")) {
603
} else if (sClefLine == _T("C4")) {
605
} else if (sClefLine == _T("G2")) {
607
} else if (sClefLine == _T("F3")) {
609
} else if (sClefLine == _T("F4")) {
611
} else if (sClefLine == _T("SINCLAVE")) {
612
*pClef = eclvSinClave;
621
bool XmlDataToBarStyle(wxString sBarStyle, ETipoBarra* pType)
623
if (sBarStyle == _T("FINREPETICION")) {
624
*pType = etbBarraFinRepeticion;
625
} else if (sBarStyle == _T("INICIOREPETICION")) {
626
*pType = etbBarraInicioRepeticion;
627
} else if (sBarStyle == _T("light-heavy")) {
628
*pType = etbBarraFinal;
629
} else if (sBarStyle == _T("light-light")) {
630
*pType = etbBarraDoble;
631
} else if (sBarStyle == _T("regular")) {
632
*pType = etbBarraNormal;
633
} else if (sBarStyle == _T("heavy-light")) {
634
*pType = etbBarraInicial;
635
} else if (sBarStyle == _T("DOBLEREPETICION")) {
636
*pType = etbDobleRepeticion;
638
//! @todo Add styles dotted, heavy, heavy-heavy, none
639
//! @todo Remove styles FINREPETICION, INICIOREPETICION, DOBLEREPETICION
647
void LoadCboBoxWithNoteNames(wxComboBox* pCboBox, lmPitch nSelNote)
651
for (i=1; i < 60; i++) {
652
pCboBox->Append( GetNoteNamePhysicists((lmPitch) i) );
654
pCboBox->SetValue( GetNoteNamePhysicists(nSelNote) );
658
void LoadCboBoxWithNoteNames(wxComboBox* pCboBox, wxString sNoteName)
662
for (i=1; i < 60; i++) {
663
pCboBox->Append( GetNoteNamePhysicists((lmPitch) i) );
665
pCboBox->SetValue( sNoteName );