Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/notationmanager/StandardNotationFactory.java


1   /*
2   ================================================================================
3   
4     FILE:  StandardNotationFactoryImpl.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Standard implementation of NotationFactory
13    
14    PROGRAMMERS:
15    
16      Daniel Azuma (DA)  <dazuma@kagi.com>
17    
18    COPYRIGHT:
19    
20      Copyright (C) 2003  Daniel Azuma  (dazuma@kagi.com)
21      
22      This program is free software; you can redistribute it and/or
23      modify it under the terms of the GNU General Public License as
24      published by the Free Software Foundation; either version 2
25      of the License, or (at your option) any later version.
26      
27      This program is distributed in the hope that it will be useful,
28      but WITHOUT ANY WARRANTY; without even the implied warranty of
29      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30      GNU General Public License for more details.
31      
32      You should have received a copy of the GNU General Public
33      License along with this program; if not, write to
34        Free Software Foundation, Inc.
35        59 Temple Place, Suite 330
36        Boston, MA 02111-1307 USA
37  
38  ================================================================================
39  */
40  
41  
42  package com.virtuosotechnologies.asaph.notationmanager;
43  
44  
45  import java.util.Locale;
46  import java.util.List;
47  import java.util.ArrayList;
48  import java.util.LinkedHashMap;
49  import java.util.Iterator;
50  
51  import com.virtuosotechnologies.lib.util.LocalizedStringBuilder;
52  
53  import com.virtuosotechnologies.asaph.model.notation.NotationFactory;
54  import com.virtuosotechnologies.asaph.model.notation.Note;
55  import com.virtuosotechnologies.asaph.model.notation.NoteModifier;
56  import com.virtuosotechnologies.asaph.model.notation.Interval;
57  import com.virtuosotechnologies.asaph.model.notation.Chord;
58  
59  
60  /**
61   * Standard implementation of NotationFactory
62   */
63  /*package*/ class StandardNotationFactory
64  implements
65    NotationFactory
66  {
67    private boolean isGerman_;
68    
69    private StandardNoteModifier naturalModifier_;
70    private StandardNoteModifier flatModifier_;
71    private StandardNoteModifier sharpModifier_;
72    private StandardNote defaultNote_;
73    private StandardChord emptyChord_;
74    
75    private StandardNote[] guiBaseNotes_;
76    private StandardNote[] parseBaseNotes_;
77    
78    private static final LocalizedStringBuilder strings_ =
79      new LocalizedStringBuilder(StandardNotationFactory.class, "StandardNotationStringsRB");
80    
81    private static final String STR_NoteModifier_Natural =
82      strings_.buildString("NoteModifier_Natural");
83    private static final String STR_NoteModifier_Sharp =
84      strings_.buildString("NoteModifier_Sharp");
85    private static final String STR_NoteModifier_Flat =
86      strings_.buildString("NoteModifier_Flat");
87    private static final String STR_NoteModifier_DoubleSharp =
88      strings_.buildString("NoteModifier_DoubleSharp");
89    private static final String STR_NoteModifier_DoubleFlat =
90      strings_.buildString("NoteModifier_DoubleFlat");
91    private static final String STR_Interval_Unknown =
92      strings_.buildString("Interval_Unknown");
93    
94    private LinkedHashMap longIntervalStrings_;
95    
96    
97    /*package*/ StandardNotationFactory(
98      boolean isGerman)
99    {
100     isGerman_ = isGerman;
101     
102     naturalModifier_ = new StandardNoteModifier(this, 0);
103     flatModifier_ = new StandardNoteModifier(this, -1);
104     sharpModifier_ = new StandardNoteModifier(this, 1);
105     defaultNote_ = new StandardNote(this, 0, 0, naturalModifier_, true);
106     emptyChord_ = new StandardChord(this, null, "", null, "");
107     
108     if (isGerman_)
109     {
110       guiBaseNotes_ = new StandardNote[8];
111       guiBaseNotes_[0] = new StandardNote(this, 0, 0, naturalModifier_, true);
112       guiBaseNotes_[1] = new StandardNote(this, 1, 1, naturalModifier_, true);
113       guiBaseNotes_[2] = new StandardNote(this, 1, 2, naturalModifier_, true);
114       guiBaseNotes_[3] = new StandardNote(this, 2, 3, naturalModifier_, true);
115       guiBaseNotes_[4] = new StandardNote(this, 3, 5, naturalModifier_, true);
116       guiBaseNotes_[5] = new StandardNote(this, 4, 7, naturalModifier_, true);
117       guiBaseNotes_[6] = new StandardNote(this, 5, 8, naturalModifier_, true);
118       guiBaseNotes_[7] = new StandardNote(this, 6, 10, naturalModifier_, true);
119       parseBaseNotes_ = new StandardNote[8];
120       parseBaseNotes_[0] = guiBaseNotes_[0];
121       parseBaseNotes_[1] = guiBaseNotes_[1];
122       parseBaseNotes_[2] = guiBaseNotes_[3];
123       parseBaseNotes_[3] = guiBaseNotes_[4];
124       parseBaseNotes_[4] = guiBaseNotes_[5];
125       parseBaseNotes_[5] = guiBaseNotes_[6];
126       parseBaseNotes_[6] = guiBaseNotes_[7];
127       parseBaseNotes_[7] = guiBaseNotes_[2];
128     }
129     else
130     {
131       guiBaseNotes_ = new StandardNote[7];
132       guiBaseNotes_[0] = new StandardNote(this, 0, 0, naturalModifier_, true);
133       guiBaseNotes_[1] = new StandardNote(this, 1, 2, naturalModifier_, true);
134       guiBaseNotes_[2] = new StandardNote(this, 2, 3, naturalModifier_, true);
135       guiBaseNotes_[3] = new StandardNote(this, 3, 5, naturalModifier_, true);
136       guiBaseNotes_[4] = new StandardNote(this, 4, 7, naturalModifier_, true);
137       guiBaseNotes_[5] = new StandardNote(this, 5, 8, naturalModifier_, true);
138       guiBaseNotes_[6] = new StandardNote(this, 6, 10, naturalModifier_, true);
139       parseBaseNotes_ = new StandardNote[7];
140       parseBaseNotes_[0] = guiBaseNotes_[0];
141       parseBaseNotes_[1] = guiBaseNotes_[1];
142       parseBaseNotes_[2] = guiBaseNotes_[2];
143       parseBaseNotes_[3] = guiBaseNotes_[3];
144       parseBaseNotes_[4] = guiBaseNotes_[4];
145       parseBaseNotes_[5] = guiBaseNotes_[5];
146       parseBaseNotes_[6] = guiBaseNotes_[6];
147     }
148     
149     longIntervalStrings_ = new LinkedHashMap();
150     longIntervalStrings_.put(new StandardInterval(this, 0, -1),
151       strings_.buildString("Interval_DimUnison"));
152     longIntervalStrings_.put(new StandardInterval(this, 0, 0),
153       strings_.buildString("Interval_PerfUnison"));
154     longIntervalStrings_.put(new StandardInterval(this, 0, 1),
155       strings_.buildString("Interval_AugUnison"));
156     longIntervalStrings_.put(new StandardInterval(this, 1, 0),
157       strings_.buildString("Interval_DimSecond"));
158     longIntervalStrings_.put(new StandardInterval(this, 1, 1),
159       strings_.buildString("Interval_MinSecond"));
160     longIntervalStrings_.put(new StandardInterval(this, 1, 2),
161       strings_.buildString("Interval_MajSecond"));
162     longIntervalStrings_.put(new StandardInterval(this, 1, 3),
163       strings_.buildString("Interval_AugSecond"));
164     longIntervalStrings_.put(new StandardInterval(this, 2, 2),
165       strings_.buildString("Interval_DimThird"));
166     longIntervalStrings_.put(new StandardInterval(this, 2, 3),
167       strings_.buildString("Interval_MinThird"));
168     longIntervalStrings_.put(new StandardInterval(this, 2, 4),
169       strings_.buildString("Interval_MajThird"));
170     longIntervalStrings_.put(new StandardInterval(this, 2, 5),
171       strings_.buildString("Interval_AugThird"));
172     longIntervalStrings_.put(new StandardInterval(this, 3, 4),
173       strings_.buildString("Interval_DimFourth"));
174     longIntervalStrings_.put(new StandardInterval(this, 3, 5),
175       strings_.buildString("Interval_PerfFourth"));
176     longIntervalStrings_.put(new StandardInterval(this, 3, 6),
177       strings_.buildString("Interval_AugFourth"));
178     longIntervalStrings_.put(new StandardInterval(this, 4, 6),
179       strings_.buildString("Interval_DimFifth"));
180     longIntervalStrings_.put(new StandardInterval(this, 4, 7),
181       strings_.buildString("Interval_PerfFifth"));
182     longIntervalStrings_.put(new StandardInterval(this, 4, 8),
183       strings_.buildString("Interval_AugFifth"));
184     longIntervalStrings_.put(new StandardInterval(this, 5, 7),
185       strings_.buildString("Interval_DimSixth"));
186     longIntervalStrings_.put(new StandardInterval(this, 5, 8),
187       strings_.buildString("Interval_MinSixth"));
188     longIntervalStrings_.put(new StandardInterval(this, 5, 9),
189       strings_.buildString("Interval_MajSixth"));
190     longIntervalStrings_.put(new StandardInterval(this, 5, 10),
191       strings_.buildString("Interval_AugSixth"));
192     longIntervalStrings_.put(new StandardInterval(this, 6, 9),
193       strings_.buildString("Interval_DimSeventh"));
194     longIntervalStrings_.put(new StandardInterval(this, 6, 10),
195       strings_.buildString("Interval_MinSeventh"));
196     longIntervalStrings_.put(new StandardInterval(this, 6, 11),
197       strings_.buildString("Interval_MajSeventh"));
198     longIntervalStrings_.put(new StandardInterval(this, 6, 12),
199       strings_.buildString("Interval_AugSeventh"));
200   }
201   
202   
203   /*package*/ String getLongStringForNoteModifierValue(
204     int value)
205   {
206     if (value == 0) return STR_NoteModifier_Natural;
207     if (value == 1) return STR_NoteModifier_Sharp;
208     if (value == -1) return STR_NoteModifier_Flat;
209     if (value == 2) return STR_NoteModifier_DoubleSharp;
210     if (value == -2) return STR_NoteModifier_DoubleFlat;
211     
212     if (value > 0)
213     {
214       return strings_.buildString("NoteModifier_MultiSharps", new Integer(value));
215     }
216     else
217     {
218       return strings_.buildString("NoteModifier_MultiFlats", new Integer(-value));
219     }
220   }
221   
222   
223   /*package*/ String getShortStringForNoteModifierValue(
224     int value)
225   {
226     if (value == 0) return "";
227     if (value == 1) return "#";
228     if (value == -1) return "b";
229     if (value == 2) return "x";
230     if (value == -2) return "bb";
231     
232     StringBuffer sb = new StringBuffer();
233     if (value > 0)
234     {
235       for (int i=0; i<value; ++i)
236       {
237         sb.append('#');
238       }
239     }
240     else
241     {
242       for (int i=0; i>value; --i)
243       {
244         sb.append('b');
245       }
246     }
247     return new String(sb);
248   }
249   
250   
251   /*package*/ String getStringForNote(
252     int letterValue,
253     int pitchValue,
254     StandardNoteModifier modifier,
255     boolean isCaps)
256   {
257     char ch;
258     if (isGerman_ && letterValue == 1 && pitchValue >= 2)
259     {
260       ch = 'H';
261     }
262     else
263     {
264       ch = (char)('A'+letterValue);
265     }
266     if (!isCaps)
267     {
268       ch = (char)(ch+'a'-'A');
269     }
270     StringBuffer sb = new StringBuffer();
271     sb.append(ch);
272     sb.append(getShortStringForNoteModifierValue(modifier.getValue()));
273     return new String(sb);
274   }
275   
276   
277   /*package*/ StandardNote rawCreateNote(
278     int letterValue,
279     int basePitchValue,
280     int modifierValue,
281     boolean isCaps)
282   {
283     int nPitchValue = basePitchValue+modifierValue;
284     if (isGerman_ && letterValue == 1)
285     {
286       if (basePitchValue == 2 && nPitchValue <= 1)
287       {
288         // Flattening an "H" and turning it into a "B"
289         ++modifierValue;
290       }
291       else if (basePitchValue == 1 && nPitchValue >= 2)
292       {
293         // Sharpening a "B" and turning it into an "H"
294         --modifierValue;
295       }
296     }
297     return new StandardNote(this, letterValue, nPitchValue,
298       new StandardNoteModifier(this, modifierValue), isCaps);
299   }
300   
301   
302   /*package*/ String getLongStringForInterval(
303     StandardInterval interval)
304   {
305     String str = (String)longIntervalStrings_.get(interval);
306     if (str == null)
307     {
308       str = STR_Interval_Unknown;
309     }
310     return str;
311   }
312   
313   
314   /*package*/ String getStringForChord(
315     StandardNote mainNote,
316     String mainType,
317     StandardNote bassNote,
318     String bassType)
319   {
320     String mainNoteStr = "";
321     if (mainNote != null)
322     {
323       mainNoteStr = mainNote.generateString();
324       if (bassNote != null)
325       {
326         return mainNoteStr+mainType+'/'+bassNote.generateString()+bassType;
327       }
328     }
329     return mainNoteStr+mainType;
330   }
331   
332   
333   /*package*/ StandardNote parseNoteFromScanner(
334     StringScanner str)
335   {
336     char ch = str.nextChar();
337     if (ch == 0)
338     {
339       return null;
340     }
341     boolean isCaps = true;
342     if (ch >= 'a' && ch <= 'h')
343     {
344       ch = (char)(ch+'A'-'a');
345       isCaps = false;
346     }
347     if (ch < 'A' || ch > 'H' || (!isGerman_ && ch == 'H'))
348     {
349       str.pushBack();
350       return null;
351     }
352     StandardNote note = parseBaseNotes_[ch-'A'];
353     ch = str.nextChar();
354     if (ch == 0)
355     {
356       return new StandardNote(this, note.getLetterValue(), note.getPitchValue(),
357         (StandardNoteModifier)note.getNoteModifier(), isCaps);
358     }
359     else if (ch == 'X' || ch == 'x')
360     {
361       return rawCreateNote(note.getLetterValue(), note.getPitchValue(), 2, isCaps);
362     }
363     else if (ch == 'b' || ch == 'B')
364     {
365       int mod = -1;
366       while (true)
367       {
368         ch = str.nextChar();
369         if (ch == 0)
370         {
371           return rawCreateNote(note.getLetterValue(), note.getPitchValue(),
372             mod, isCaps);
373         }
374         else if (ch != 'b' && ch != 'B')
375         {
376           str.pushBack();
377           return rawCreateNote(note.getLetterValue(), note.getPitchValue(),
378             mod, isCaps);
379         }
380         --mod;
381       }
382     }
383     else if (ch == '#')
384     {
385       int mod = 1;
386       while (true)
387       {
388         ch = str.nextChar();
389         if (ch == 0)
390         {
391           return rawCreateNote(note.getLetterValue(), note.getPitchValue(),
392             mod, isCaps);
393         }
394         else if (ch != '#')
395         {
396           str.pushBack();
397           return rawCreateNote(note.getLetterValue(), note.getPitchValue(),
398             mod, isCaps);
399         }
400         ++mod;
401       }
402     }
403     else
404     {
405       str.pushBack();
406       return new StandardNote(this, note.getLetterValue(), note.getPitchValue(),
407         (StandardNoteModifier)note.getNoteModifier(), isCaps);
408     }
409   }
410   
411   
412   /*package*/ StandardChord parseChordFromScanner(
413     StringScanner scan)
414   {
415     StandardNote note = parseNoteFromScanner(scan);
416     StandardNote bass = null;
417     StringBuffer typebuf = new StringBuffer();
418     StringBuffer type2buf = new StringBuffer();
419     while (true)
420     {
421       char ch = scan.nextChar();
422       if (ch == 0)
423       {
424         break;
425       }
426       else if (ch == ' ' || ch == '\t')
427       {
428         scan.pushBack();
429         break;
430       }
431       else if (ch == '/' && bass == null)
432       {
433         bass = parseNoteFromScanner(scan);
434         if (bass == null)
435         {
436           typebuf.append(ch);
437         }
438       }
439       else if (bass == null)
440       {
441         typebuf.append(ch);
442       }
443       else
444       {
445         type2buf.append(ch);
446       }
447     }
448     return new StandardChord(this, note, new String(typebuf), bass, new String(type2buf));
449   }
450   
451   
452   /*package*/ StandardNote addIntervalToNote(
453     int letterValue,
454     int pitchValue,
455     boolean isCaps,
456     int letterDiff,
457     int pitchDiff)
458   {
459     letterValue += letterDiff;
460     int jumps = letterValue / 7;
461     letterValue %= 7;
462     if (letterValue < 0)
463     {
464       letterValue += 7;
465       --jumps;
466     }
467     pitchValue += pitchDiff - jumps*12;
468     StandardNote baseNote = parseBaseNotes_[letterValue];
469     int basePitch = baseNote.getPitchValue();
470     if (isGerman_ && letterValue == 1 && basePitch < pitchValue)
471     {
472       baseNote = parseBaseNotes_[7];
473       basePitch = baseNote.getPitchValue();
474     }
475     return new StandardNote(this, letterValue, pitchValue,
476       new StandardNoteModifier(this, pitchValue-basePitch), isCaps);
477   }
478   
479   
480   // Gui builder methods
481   
482   /**
483    * Get an array of the common intervals.
484    * This is used to construct choosers for intervals.
485    *
486    * @return array of Interval
487    */
488   public Interval[] getCommonIntervals()
489   {
490     Interval[] ret = new Interval[longIntervalStrings_.size()];
491     int index = 0;
492     for (Iterator iter = longIntervalStrings_.keySet().iterator(); iter.hasNext(); )
493     {
494       ret[index++] = (Interval)iter.next();
495     }
496     return ret;
497   }
498   
499   
500   /**
501    * Get an array of the base notes-- that is, with a default modifier (usually natural).
502    * This is used to construct choosers for notes.
503    *
504    * @return array of Note
505    */
506   public Note[] getBaseNotes()
507   {
508     Note[] ret = new Note[guiBaseNotes_.length];
509     System.arraycopy(guiBaseNotes_, 0, ret, 0, guiBaseNotes_.length);
510     return ret;
511   }
512   
513   
514   /**
515    * Get an array of common modifiers for the given base note.
516    * This is used to construct choosers for notes.
517    *
518    * @param note Note to modify
519    * @return array of common modifiers for the given note.
520    */
521   public NoteModifier[] getCommonModifiersForNote(
522     Note note)
523   {
524     StandardNote snote = (StandardNote)note;
525     if (isGerman_ && snote.getLetterValue() == 1)
526     {
527       if (snote.getPitchValue() >= 2)
528       {
529         NoteModifier[] ret = new NoteModifier[2];
530         ret[0] = naturalModifier_;
531         ret[1] = sharpModifier_;
532         return ret;
533       }
534       else
535       {
536         NoteModifier[] ret = new NoteModifier[1];
537         ret[0] = naturalModifier_;
538         return ret;
539       }
540     }
541     else
542     {
543       NoteModifier[] ret = new NoteModifier[3];
544       ret[0] = naturalModifier_;
545       ret[1] = sharpModifier_;
546       ret[2] = flatModifier_;
547       return ret;
548     }
549   }
550   
551   
552   // Other note modifier methods methods
553   
554   /**
555    * Is the given modifier allowed for the given note?
556    *
557    * @param n the note
558    * @return default NoteModifier
559    */
560   public boolean isModifierAllowedForNote(
561     Note note,
562     NoteModifier mod)
563   {
564     StandardNote snote = (StandardNote)note;
565     StandardNoteModifier smod = (StandardNoteModifier)mod;
566     if (isGerman_ && snote.getLetterValue() == 1)
567     {
568       if (snote.getPitchValue() >= 2 && smod.getValue() < 0)
569       {
570         return false;
571       }
572       if (snote.getPitchValue() <= 1 && smod.getValue() > 0)
573       {
574         return false;
575       }
576     }
577     return true;
578   }
579   
580   
581   /**
582    * Get the default NoteModifier (typically natural) for the given note.
583    *
584    * @param n the note
585    * @return default NoteModifier
586    */
587   public NoteModifier getDefaultNoteModifierFor(
588     Note n)
589   {
590     return naturalModifier_;
591   }
592   
593   
594   // Parsing methods
595   
596   /**
597    * Parse a Note from a String
598    *
599    * @param str source String
600    * @return resulting Note
601    */
602   public Note parseNote(
603     String str)
604   {
605     StringScanner scan = new StringScanner(str);
606     StandardNote note = parseNoteFromScanner(scan);
607     if (scan.nextChar() == 0)
608     {
609       return note;
610     }
611     else
612     {
613       return null;
614     }
615   }
616   
617   
618   /**
619    * Parse a Note array from a String
620    *
621    * @param str source String
622    * @return resulting Note array
623    */
624   public Note[] parseNoteArray(
625     String str)
626   {
627     List list = new ArrayList();
628     StringScanner scan = new StringScanner(str);
629     while (true)
630     {
631       StandardNote note = parseNoteFromScanner(scan);
632       if (note == null)
633       {
634         break;
635       }
636       list.add(note);
637       if (scan.nextChar() != ' ')
638       {
639         break;
640       }
641     }
642     Note[] ret = new Note[list.size()];
643     list.toArray(ret);
644     return ret;
645   }
646   
647   
648   /**
649    * Parse a Chord from a String
650    *
651    * @param str source String
652    * @return resulting Chord
653    */
654   public Chord parseChord(
655     String str)
656   {
657     StringScanner scan = new StringScanner(str);
658     StandardChord chord = parseChordFromScanner(scan);
659     if (scan.nextChar() == 0)
660     {
661       return chord;
662     }
663     else
664     {
665       return null;
666     }
667   }
668   
669   
670   /**
671    * Parse a Chord array from a String
672    *
673    * @param str source String
674    * @return resulting Chord array
675    */
676   public Chord[] parseChordArray(
677     String str)
678   {
679     List list = new ArrayList();
680     StringScanner scan = new StringScanner(str);
681     
682     boolean isAllEmpty = true;
683     while (true)
684     {
685       StandardChord chord = parseChordFromScanner(scan);
686       if (isAllEmpty && !chord.isEmpty())
687       {
688         isAllEmpty = false;
689       }
690       list.add(chord);
691       char ch = scan.nextChar();
692       if (ch == 0)
693       {
694         break;
695       }
696     }
697     
698     if (isAllEmpty)
699     {
700       list.remove(list.size()-1);
701     }
702     Chord[] ret = new Chord[list.size()];
703     list.toArray(ret);
704     return ret;
705   }
706   
707   
708   /**
709    * Generate a string for a chord array
710    *
711    * @param chords array of Chords
712    * @return String
713    */
714   public String unparseChordArray(
715     Chord[] chords)
716   {
717     StringBuffer sb = new StringBuffer();
718     boolean firstChord = true;
719     boolean isAllEmpty = true;
720     for (int i=0; i<chords.length; ++i)
721     {
722       if (firstChord)
723       {
724         firstChord = false;
725       }
726       else
727       {
728         sb.append(' ');
729       }
730       sb.append(chords[i].generateString());
731       if (isAllEmpty && !chords[i].isEmpty())
732       {
733         isAllEmpty = false;
734       }
735     }
736     if (isAllEmpty && chords.length > 0)
737     {
738       sb.append(' ');
739     }
740     return new String(sb);
741   }
742   
743   
744   // Convenience constructors
745   
746   /**
747    * Construct an empty Chord
748    *
749    * @return new empty Chord
750    */
751   public Chord getEmptyChord()
752   {
753     return emptyChord_;
754   }
755   
756   
757   /**
758    * Construct a default Note
759    *
760    * @return new Note
761    */
762   public Note getDefaultNote()
763   {
764     return defaultNote_;
765   }
766 }