1
//--------------------------------------------------------------------------------------
2
// LenMus Phonascus: The teacher of music
3
// Copyright (c) 2002-2007 Cecilio Salmeron
5
// This program is free software; you can redistribute it and/or modify it under the
6
// terms of the GNU General Public License as published by the Free Software Foundation;
7
// either version 2 of the License, or (at your option) any later version.
9
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
10
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11
// PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
// You should have received a copy of the GNU General Public License along with this
14
// program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
15
// Fifth Floor, Boston, MA 02110-1301, USA.
17
// For any comment, suggestion or feature request, please contact the manager of
18
// the project at cecilios@users.sourceforge.net
20
//-------------------------------------------------------------------------------------
25
#ifndef __THEOMUSICREADINGCTROLPARAMS_H__ //to avoid nested includes
26
#define __THEOMUSICREADINGCTROLPARAMS_H__
28
// For compilers that support precompilation, includes "wx/wx.h".
29
#include "wx/wxprec.h"
39
#include "wx/html/htmlwin.h"
40
#include "ObjectParams.h"
41
#include "../exercises/ScoreConstrains.h"
42
#include "../ldp_parser/AuxString.h"
44
//! enum assigning name to the score generation settings source.
46
Four different ways for choosing the settings:
48
1. By level and lesson: Useful for what? It was necessary with old non-html
49
organization. Now for each lesson there will be an html page and the
50
score object will have all necessary information for that lesson. So method
51
3 will replace this one.
53
2. Personal settings dialog: the user selects the rithmic patterns to generate.
54
Valid only to generate simple repetitive patterns. Composer must have
55
knowledge for completing bars with rest or single notes.
57
3. Pararameters in html object: the parameters must include all necesary data.
58
Score generation based only on received fragments.
60
4. Reading notes exercises: the parameters are fixed for this exercise (parameters
61
the html object) but certain values (clefs, notes range) would need
64
Free exercises page will be based only on method 2 in coherence with its purpose
65
(free exercises, user customizable). For practising an specific level/lesson the
66
user must choose the corresponding book/page. In these pages it would be allowed
67
to customize settings by adding/removing fragments or changing clefs and note ranges.
71
/*! This class pack all parameters to set up a Music Reading exercise.
72
The contained lmScoreConstrains object has the constraints for the 'ByProgram'
73
settings mode (default mode). For other modes ('UserSettings' and 'ReadingNotes')
74
the settings must be read/setup by the TheoMusicReadingCtrol object.
76
class lmTheoMusicReadingCtrolParms : public lmObjectParams
79
lmTheoMusicReadingCtrolParms(const wxHtmlTag& tag, int nWidth, int nHeight,
80
int nPercent, long nStyle);
81
~lmTheoMusicReadingCtrolParms();
83
void AddParam(const wxHtmlTag& tag);
84
void CreateHtmlCell(wxHtmlWinParser *pHtmlParser);
87
bool AnalyzeClef(wxString sLine);
88
bool AnalyzeTime(wxString sLine);
89
bool AnalyzeKeys(wxString sLine);
90
bool AnalyzeFragments(wxString sLine);
94
// html object window attributes
96
lmScoreConstrains* m_pConstrains;
97
lmMusicReadingCtrolOptions* m_pOptions;
98
wxString m_sParamErrors;
100
DECLARE_NO_COPY_CLASS(lmTheoMusicReadingCtrolParms)
105
lmTheoMusicReadingCtrolParms::lmTheoMusicReadingCtrolParms(const wxHtmlTag& tag, int nWidth, int nHeight,
106
int nPercent, long nStyle)
107
: lmObjectParams(tag, nWidth, nHeight, nPercent)
110
// html object window attributes
111
m_nWindowStyle = nStyle;
113
// construct constraints object
114
m_pConstrains = new lmScoreConstrains();
117
m_pOptions = new lmMusicReadingCtrolOptions();
120
m_sParamErrors = _T(""); //no errors
125
lmTheoMusicReadingCtrolParms::~lmTheoMusicReadingCtrolParms()
127
//Constrains and options will be deleted by the Ctrol. DO NOT DELETE THEM HERE
128
//IF THE CONTROL HAS BEEN CREATED
129
if (m_sParamErrors != _T("")) {
130
if (m_pConstrains) delete m_pConstrains;
131
if (m_pOptions) delete m_pOptions;
136
void lmTheoMusicReadingCtrolParms::AddParam(const wxHtmlTag& tag)
138
/*! @page MusicReadingCtrolParams
141
Params for lmScoreCtrol - html object type="Application/LenMusTheoMusicReading"
144
optional params to include controls: (not yet implemented marked as [])
145
--------------------------------------
147
control_play Include 'play' link. Default: do not include it.
148
Value="play label|stop playing label". i.e.: "Play|Stop" Stop label
149
is optional. Default labels: "Play|Stop"
151
control_solfa Include 'solfa' link. Default: do not include it.
152
Value="music read label|stop music reading label". i.e.:
153
"Play|Stop". Stop label is optional.
154
Default labels: "Read|Stop"
156
control_settings Value="[key for storing the settings]"
157
This param forces to include the 'settings' link. The
158
key will be used both as the key for saving the user settings
159
and as a tag to select the Setting Dialog options to allow.
161
control_go_back URL, i.e.: "v2_L2_MusicReading_203.htm"
163
metronome Set a fixed metronome rate to play this piece of music
164
Value="MM number". Default: user value in metronome control
167
params to set up the score composer:
168
------------------------------------
170
fragment* one param for each fragment to use
172
clef* one param for each allowed clef. It includes the pitch scope.
174
time a list of allowed time signatures, i.e.: "68,98,128"
176
key keyword "all" or a list of allowed key signatures, i.e.: "Do,Fas"
178
max_interval a number indicating the maximum allowed interval for two consecutive notes
181
@todo: update the example
183
------------------------------------
185
<object type="Application/LenMusTheoMusicReading" width="100%" height="300" border="0">
186
<param name="control" value="play">
187
<param name="label_play" value="Play|Stop">
188
<param name="control" value="solfa">
189
<param name="mode" value="PersonalSettings">
190
<param name="mode" value="NotesReading">
191
<param name="fragment" value="68,98;(n * n)(n * c +l)(g (n * c)(n * c)(n * c))">
192
<param name="fragment" value="68,98;(n * c)(n * n +l)(g (n * c)(n * c)(n * c))">
193
<param name="fragment" value="68,98;(n * n)(n * c)">
194
<param name="fragment" value="68,98;(g (n * c)(n * c)(n * c))">
195
<param name="clef" value="Sol;a3;a5">
196
<param name="clef" value="Fa4;a2;e4">
197
<param name="time" value="68,98,128">
198
<param name="key" value="all">
199
<param name="max_interval" value="4">
206
wxString sName = wxEmptyString;
207
wxString sValue = wxEmptyString;
209
// scan name and value
210
if (!tag.HasParam(wxT("NAME"))) return; // ignore param tag if no name attribute
211
sName = tag.GetParam(_T("NAME"));
212
sName.UpperCase(); //convert to upper case
214
if (!tag.HasParam(_T("VALUE"))) return; // ignore param tag if no value attribute
217
if ( sName == _T("CONTROL_PLAY") ) {
218
m_pOptions->SetControlPlay(true, tag.GetParam(_T("VALUE")) );
222
else if ( sName == _T("CONTROL_SOLFA") ) {
223
m_pOptions->SetControlSolfa(true, tag.GetParam(_T("VALUE")) );
226
// "Go back to theory" link
227
else if ( sName == _T("CONTROL_GO_BACK") ) {
228
m_pOptions->SetGoBackURL( tag.GetParam(_T("VALUE") ));
232
else if ( sName == _T("CONTROL_SETTINGS") ) {
233
m_pOptions->SetControlSettings(true, tag.GetParam(_T("VALUE")) );
234
m_pConstrains->SetSection( tag.GetParam(_T("VALUE") ));
238
else if ( sName == _T("METRONOME") ) {
239
wxString sMM = tag.GetParam(_T("VALUE"));
241
bool fOK = sMM.ToLong(&nMM);
242
if (!fOK || nMM < 0 ) {
243
m_sParamErrors += wxString::Format(
244
_("Invalid param value in:\n<param %s >\n \
245
Invalid value = %s \n \
246
Acceptable values: numeric, greater than 0\n"),
247
tag.GetAllParams(), tag.GetParam(_T("VALUE")) );
250
m_pConstrains->SetMetronomeMM(nMM);
254
//fragments the list of fragmens to use
255
// <param name="fragment" value="68,98;(n * n)(n * c +l)(g (n * c)(n * c)(n * c))">
256
// <param name="fragment" value="68,98;(n * c)(n * n +l)(g (n * c)(n * c)(n * c))">
257
// <param name="fragment" value="68,98;(n * n)(n * c)">
258
// <param name="fragment" value="68,98;(g (n * c)(n * c)(n * c))">
260
else if ( sName == _T("FRAGMENT") ) {
261
wxString sFragments = tag.GetParam(_T("VALUE"));
262
AnalyzeFragments(sFragments);
265
//clef* one param for each allowed clef. It includes the pitch scope.
266
// <param name="clef" value="Sol;a3;a5" />
267
// <param name="clef" value="Fa4;a2;e4" />
269
else if ( sName == _T("CLEF") ) {
270
wxString sClef = tag.GetParam(_T("VALUE"));
271
if (AnalyzeClef(sClef)) {
272
m_sParamErrors += wxString::Format(
273
_("Invalid param value in:\n<param %s >\n \
274
Invalid value = %s \n \
275
Acceptable format: <Clef,LowerNote,UpperNote> \n \
276
Acceptable clef values: Sol | Fa4 | Fa3 | Do4 | Do3 | Do2 | Do1 \n \
277
Acceptable note pitch: c0 - c9"),
278
tag.GetAllParams(), tag.GetParam(_T("VALUE")) );
282
//time a list of allowed time signatures, i.e.: "68,98,128"
283
// <param name="time" value="68,98,128">
285
else if ( sName == _T("TIME") ) {
286
wxString sTime = tag.GetParam(_T("VALUE"));
287
if (AnalyzeTime(sTime)) {
288
m_sParamErrors += wxString::Format(
289
_("Invalid param value in:\n<param %s >\n \
290
Invalid value = %s \n \
291
Acceptable format: list of time signatures \n"),
292
tag.GetAllParams(), tag.GetParam(_T("VALUE")) );
296
//key keyword "all" or a list of allowed key signatures, i.e.: "Do,Fas"
297
// <param name="key" value="all">
299
else if ( sName == _T("KEY") ) {
300
wxString sKeys = tag.GetParam(_T("VALUE"));
301
if (AnalyzeKeys(sKeys)) {
302
m_sParamErrors += wxString::Format(
303
_("Invalid param value in:\n<param %s >\n \
304
Invalid value = %s \n \
305
Acceptable format: list of key signatures or keyword 'all' \n"),
306
tag.GetAllParams(), tag.GetParam(_T("VALUE")) );
310
//maxGroupInterval a number
311
else if ( sName == _T("MAX_INTERVAL") ) {
312
wxString sMaxInterval = tag.GetParam(_T("VALUE"));
314
bool fOK = sMaxInterval.ToLong(&nMaxInterval);
315
if (!fOK || nMaxInterval < 0 ) {
316
m_sParamErrors += wxString::Format(
317
_("Invalid param value in:\n<param %s >\n \
318
Invalid value = %s \n \
319
Acceptable values: numeric, greater than 0\n"),
320
tag.GetAllParams(), tag.GetParam(_T("VALUE")) );
323
m_pConstrains->SetMaxInterval((int)nMaxInterval);
329
m_sParamErrors += wxString::Format(
330
_("lmTheoMusicReadingCtrol. Unknown param: <param %s >\n"),
331
tag.GetAllParams() );
335
void lmTheoMusicReadingCtrolParms::CreateHtmlCell(wxHtmlWinParser *pHtmlParser)
337
//The <object> tag has been read. If param 'control_settings' has been specified
338
// configuration values must be loaded from the specified section key
339
m_pConstrains->LoadSettings();
341
//verify that all necessary html params has been specified
343
m_sParamErrors += m_pConstrains->Verify();
344
if (m_sParamErrors != _T("")) {
345
// there are errors: display a text box with the error message
346
pWnd = new wxTextCtrl((wxWindow*)pHtmlParser->GetWindowInterface()->GetHTMLWindow(), -1, m_sParamErrors,
347
wxPoint(0,0), wxSize(300, 100), wxTE_MULTILINE);
350
// create the TheoMusicReadingCtrol
351
pWnd = new lmTheoMusicReadingCtrol((wxWindow*)pHtmlParser->GetWindowInterface()->GetHTMLWindow(), -1,
352
m_pOptions, m_pConstrains, wxPoint(0,0), wxSize(m_nWidth, m_nHeight), m_nWindowStyle );
355
pHtmlParser->GetContainer()->InsertCell(new wxHtmlWidgetCell(pWnd, m_nPercent));
359
/// returns true if error
360
bool lmTheoMusicReadingCtrolParms::AnalyzeClef(wxString sLine)
365
int iSemicolon = sLine.Find(_T(";"));
366
wxString sClef = sLine.Left(iSemicolon);
367
EClefType nClef = LDPNameToClef(sClef);
368
if (nClef == (EClefType)-1) return true; //error
371
sLine = sLine.Mid(iSemicolon+1);
372
iSemicolon = sLine.Find(_T(";"));
373
wxString sLowerScope = sLine.Left(iSemicolon);
376
wxString sUpperScope = sLine.Mid(iSemicolon + 1);
378
//Update information for this clef
379
lmClefConstrain* pClefs = m_pConstrains->GetClefConstrains();
380
pClefs->SetValid(nClef, true);
381
pClefs->SetLowerPitch(nClef, sLowerScope);
382
pClefs->SetUpperPitch(nClef, sUpperScope);
384
return false; //no error
388
/// returns true if error
389
bool lmTheoMusicReadingCtrolParms::AnalyzeTime(wxString sLine)
391
//i.e.: "98" , "38,68,128" , "24,44"
393
//build time signatures constraints object
394
lmTimeSignConstrains* pTimeSigns = new lmTimeSignConstrains();
395
if (pTimeSigns->SetConstrains(sLine)) return true;
397
//Replace information about allowed time signatures
398
lmTimeSignConstrains* pOldTimeSigns = m_pConstrains->GetTimeSignConstrains();
400
ETimeSignature nTime;
401
for (i=lmMIN_TIME_SIGN; i <= lmMAX_TIME_SIGN; i++) {
402
nTime = (ETimeSignature)i;
403
pOldTimeSigns->SetValid(nTime, pTimeSigns->IsValid(nTime) );
407
return false; //no error
411
/// returns true if error
412
bool lmTheoMusicReadingCtrolParms::AnalyzeKeys(wxString sLine)
414
//i.e.: "all" , "do,sol,fa,"
416
if (sLine == _T("all")) {
417
// allow all key signatures
418
lmKeyConstrains* pKeys = m_pConstrains->GetKeyConstrains();
420
for (i=0; i <= earmFa; i++) {
421
pKeys->SetValid((EKeySignatures)i, true);
426
//analyze and set key signatures
427
lmKeyConstrains* pKeys = m_pConstrains->GetKeyConstrains();
429
//loop to get all keys
433
while (sLine != _T("")) {
435
iColon = sLine.Find(_T(","));
437
sKey = sLine.Left(iColon);
438
sLine = sLine.Mid(iColon + 1); //skip the colon
444
nKey = LDPInternalNameToKey(sKey);
445
if (nKey == (EKeySignatures)-1) return true;
446
pKeys->SetValid(nKey, true);
450
return false; //no error
454
/// returns true if error
455
bool lmTheoMusicReadingCtrolParms::AnalyzeFragments(wxString sLine)
457
//i.e.: "24,34;(s c)(n * n)(n * s g+)(n * s )(n * c g-)(s c)"
459
//get time signatures
460
int iSemicolon = sLine.Find(_T(";"));
461
wxString sTimeSign = sLine.Left(iSemicolon);
464
wxString sFragment = sLine.Mid(iSemicolon + 1); //skip the semicolon and take the rest
466
//build time signatures constraints object
467
lmTimeSignConstrains* pTimeSigns = new lmTimeSignConstrains();
468
if (pTimeSigns->SetConstrains(sTimeSign)) {
469
m_sParamErrors += wxString::Format(_("Error in fragment. Invalid time signature list '%s'\nIn fragment: '%s'\n"),
470
sTimeSign, sFragment);
473
// verify fragment to avoid program failures
474
lmLDPParser parserLDP;
475
//! @todo strong verification
476
//lmLDPNode* pRoot = parserLDP.ParseText(sFragment);
478
if (!parserLDP.ParenthesisMatch(sFragment)) {
479
m_sParamErrors += wxString::Format(_("Invalid fragment. Unmatched parenthesis: '%s'\n"), sFragment);
482
if (sFragment.Find(_T("(g (")) != -1 || sFragment.Find(_T("(g(")) != -1) {
483
m_sParamErrors += wxString::Format(_("Invalid fragment. Old G syntax: '%s'\n"), sFragment);
488
m_pConstrains->AddFragment(pTimeSigns, sFragment);
490
return false; //no error
494
#endif // __THEOMUSICREADINGCTROLPARAMS_H__