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

Quick Search    Search Deep

Source code: jm/music/data/Score.java


1   /*
2   
3   <This Java Class is part of the jMusic API version 1.4, February 2003.>
4   
5   
6   Copyright (C) 2000 Andrew Sorensen, Andrew Brown, Adam Kirby
7   
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or any
11  later version.
12  
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17  
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  
22  */
23  
24  package jm.music.data;
25  
26  import java.io.ObjectInputStream;
27  import java.io.ObjectOutputStream;
28  import java.io.FileInputStream;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.Serializable;
32  import java.util.Vector;
33  import java.util.Enumeration;
34  
35  import jm.audio.Instrument;
36  import jm.audio.Audio;
37  import jm.JMC;
38  import jm.midi.*;
39  import jm.util.*;
40  import jm.gui.show.*;
41  
42  /**
43   * The Score class is used to hold score data.  Score data includes
44   * is primarily made up of a vector of Part objects. Commonly score
45   * data is algorithmically generated or read from a standard MIDI file, but can also be read and saved to 
46   * file using Java's object serialization. In this way a Score's data can
47   * be saved in a more native context.
48   * To find out how to read from and write to standard MIDI files
49   * or to use object serializationcheck out 
50   * the jm.util.Read and km.util.Write classes.
51   * 
52   * @see Part 
53   * @see jm.midi.SMF
54   * @author Andrew Sorensen, Andrew Brown, Adam Kirby
55   * @version 1.0,Sun Feb 25 18:43:33  2001
56   */
57  public class Score implements JMC, Cloneable, Serializable{
58  
59    //----------------------------------------------
60      // Defaults
61    //----------------------------------------------
62  
63      public static final String DEFAULT_TITLE = "Untitled Score";
64  
65      public static final double DEFAULT_TEMPO = 60.0;
66  
67      public static final int DEFAULT_VOLUME = 100;
68  
69      public static final int DEFAULT_KEY_SIGNATURE = 0;
70  
71      public static final int DEFAULT_KEY_QUALITY = 0;
72  
73      public static final int DEFAULT_NUMERATOR = 4;
74  
75      public static final int DEFAULT_DENOMINATOR = 4;
76  
77    //----------------------------------------------
78    // Attributes
79    //----------------------------------------------
80  
81    /** the name assigned to a Score */
82    private String title;
83    /** 
84     * a Vector containing the Part objects associated with this score 
85     */
86    private Vector partList;
87    /** the speed for this score */
88    private double tempo;
89    /** the loudness for this score */
90    private int volume;
91  
92      // Possible Alternative:
93      //      Consider using the jm.music.data.KeySignature class and modifying
94      //      it to support the keyQuality field.
95  
96    /** the number of accidentals this score 
97    * negative numbers are Flats, positive numbers are Sharps
98    */
99    private int keySignature; 
100   /** 0 = major, 1 = minor, others modes not specified */
101   private int keyQuality;
102 
103     // Possible Alternative:
104     //      Consider making a TimeSignature class, containing the following
105     //      two fields.
106 
107   /** the top number of the time signature */
108   private int numerator;
109   /** the bottom number of the time signature */
110   private int denominator;
111 
112   
113   /** 
114   //----------------------------------------------
115   // Constructors
116   //----------------------------------------------
117   /**
118    * Constructs an empty score with a default name
119    */
120   public Score(){
121         this(DEFAULT_TITLE);
122   }
123 
124   /**
125    * Constructs an empty score.
126    * @param String title - give the score a name
127    */
128   public Score(String title){
129         this(title, DEFAULT_TEMPO);
130   }
131     
132   /**
133    * Constructs an empty score at the specified tempo
134    * @param tempo The speed for this score in beats per minute
135    */
136   public Score(double tempo){
137         this(DEFAULT_TITLE, tempo);
138   }
139   
140   /**
141    * Constructs an empty score.
142    * @param String title - give the score a name
143    * @param int tempo - define speed of playback in bpm
144    */
145   public Score(String title, double tempo){
146     this.title = title;
147     this.tempo = tempo;
148     this.partList = new Vector();
149         this.volume = DEFAULT_VOLUME;
150         this.keySignature = DEFAULT_KEY_SIGNATURE;
151         this.keyQuality = DEFAULT_KEY_QUALITY;
152         this.numerator = DEFAULT_NUMERATOR;
153         this.denominator = DEFAULT_DENOMINATOR;
154   }
155 
156   /**
157   * Constructs a Score containing the specified <CODE>part</CODE>.
158   *
159   * @param part  Part to be contained in the Score
160   */
161   public Score(Part part) {
162             this();
163             this.addPart(part);
164   }
165     
166   /**
167   * Constructs a Score containing the specified <CODE>part</CODE>.
168   * @param String title - give the score a name
169   * @param int tempo - define speed of playback in bpm
170   * @param part  Part to be contained in the Score
171   */
172   public Score(String title, double tempo, Part part) {
173             this(title, tempo);
174             this.addPart(part);
175   }
176 
177 
178     /**
179      * Constructs a Score containing the specified <CODE>parts</CODE>.
180      *
181      * @param parts array of Parts to be contained in the Score
182      */
183     public Score(Part[] parts) {
184         this();
185         addPartList(parts);
186     }
187 
188     /**
189      * Constructs a Score containing the specified <CODE>part</CODE> with
190      * the specified <CODE>title</CODE>.
191      *
192      * @param part  Part to be contained in the Score
193      * @param title String describing the title of the Score
194      */
195     public Score(Part part, String title) {
196         this(title);
197         addPart(part);
198     }
199 
200     /**
201      * Constructs a Score containing the specified <CODE>parts</CODE> with
202      * the specified <CODE>title</CODE>.
203      *
204      * @param parts array of Parts to be contained in the Score
205      * @param title String describing the title of the Score
206      */
207     public Score(Part[] parts, String title) {
208         this(title);
209         addPartList(parts);
210     }
211 
212     /**
213      * Constructs a Score containing the specified <CODE>part</CODE> with
214      * the specified <CODE>title</CODE> and the specified <CODE>tempo</CODE>.
215      *
216      * @param part  Part to be contained in the Score
217      * @param title String describing the title of the Score
218      * @param tempo double describing the tempo of the Score
219      */
220     public Score(Part part, String title, double tempo) {
221         this(title, tempo);
222         addPart(part);
223     }
224 
225     /**
226      * Constructs a Score containing the specified <CODE>parts</CODE> with
227      * the specified <CODE>title</CODE> and the specified <CODE>tempo</CODE>.
228      *
229      * @param parts array of Parts to be contained in the Score
230      * @param title String describing the title of the Score
231      * @param tempo double describing the tempo of the Score
232      */
233     public Score(Part[] parts, String title, double tempo) {
234         this(title, tempo);
235         addPartList(parts);
236     }
237     
238 
239   //----------------------------------------------
240   // Data Methods
241   //----------------------------------------------
242   /**
243    * Add a Track object to this Score
244    */
245   public void add(Part part){
246     this.addPart(part);
247   }
248         
249         /**
250    * Add a Track object to this Score
251    */
252   public void addPart(Part part){
253     part.setMyScore(this);
254     this.partList.addElement(part);
255   }
256 
257     /**
258      * Inserts <CODE>part</CODE> at the specified position, shifting all parts
259      * with indices greater than or equal to <CODE>index</CODE> up one position.
260      *
261      * @param part  Part to be added
262      * @param index where it is to be inserted
263      * @throws ArrayIndexOutOfBoundsException
264      *              when <CODE>index</CODE> is beyond the range of current
265      *              parts.
266      */
267     public void insertPart(Part part, int index)
268                     throws ArrayIndexOutOfBoundsException {
269         this.partList.insertElementAt(part, index);
270     part.setMyScore(this);
271     }
272   
273   /**
274    * Adds multiple parts to the score from an array of parts
275    * @param partArray
276    */
277   public void addPartList(Part[] partArray){
278       for(int i=0;i< partArray.length;i++){
279       this.addPart( partArray[i]);
280     }
281     }
282   
283   /**
284    * Deletes the specified Part in the Score
285    * @param int partNumb the index of the part to be deleted
286    */
287    public void removePart(int partNumb) {
288       Vector vct = (Vector)this.partList;
289       try{
290           vct.removeElement(vct.elementAt(partNumb));
291       } catch (RuntimeException re){
292                 System.err.println("The Part index to be deleted must be within the score.");
293             }
294   }
295     
296     /**
297     * Deletes the first occurence of the specified part in the Score.
298     * @param part  the Part object to be deleted.
299     */
300     public void removePart(Part part) {
301         this.partList.removeElement(part);
302     }
303     
304     /**
305    * Deletes the last Part added to the Score
306    */
307    public void removeLastPart() {
308       Vector vct = (Vector)this.partList;
309       vct.removeElement(vct.lastElement());
310   }
311   
312   /**
313    * Deletes all the parts previously added to the score
314    */
315    public void removeAllParts() {
316       this.partList.removeAllElements();
317   }
318 
319   /**
320    * Returns the Scores List of Tracks
321    */
322   public Vector getPartList(){
323     return partList;
324   }
325   
326   /**
327    * Returns the all Parts in this Score as a array
328    * @return Part[] An array containing all Part objects in this score
329    */
330   public Part[] getPartArray(){
331     Vector vct = (Vector) this.partList.clone();
332     Part[] partArray = new Part[vct.size()];
333     for(int i=0;i< partArray.length;i++){
334         partArray[i] = (Part) vct.elementAt(i);
335     }
336     return partArray;
337   }
338 
339   /**
340    * Get an individual Track object from its title 
341    * @param String title - the name of the Track to return
342    * @return Track answer - the Track to return
343    */
344   public Part getPart(String title){
345     Enumeration enum = partList.elements();
346     while(enum.hasMoreElements()){
347       Part part = (Part) enum.nextElement();
348       if(part.getTitle().equalsIgnoreCase(title)){
349         return part;
350       }
351     }
352     return null;
353   }
354   
355   /**
356    * Get an individual Track object from its number 
357    * @param int number - the number of the Track to return
358    * @return Track answer - the Track to return
359    */
360   public Part getPart(int number){
361     Enumeration enum = partList.elements();
362     int counter = 0;
363     while(enum.hasMoreElements()){
364       Part part = (Part) enum.nextElement();
365       if(counter == number){
366         return part;
367       }
368       counter++;
369     }
370     return null;
371   }
372   
373   
374 
375   //----------------------------------------------
376   // Utility Methods
377   //----------------------------------------------
378   /**
379    * Return the title of this Score
380    * @return String title - the name of this Score
381    */
382   public String getTitle(){
383     return title;
384   }
385   /**
386    * Assign a title to this Score
387    * @param String title - the name of this Score
388    */
389   public void setTitle(String title){
390      this.title = title;
391   }
392 
393   /**
394    * Returns the Score's tempo 
395    * @return double tempo
396    */
397   public double getTempo(){
398     return this.tempo;
399   }
400   
401   /**
402    * Sets the Score's tempo 
403    * @param double tempo
404    */
405   public void setTempo(double tempo){
406     this.tempo = tempo;
407   }
408   
409   /**
410    * Returns the Score's volume 
411    * @return int volume
412    */
413   public int getVolume(){
414     return this.volume;
415   }
416   
417   /**
418    * Sets the Score's volume 
419    * @param int volume
420    */
421   public void setVolume(int volume){
422     this.volume = volume;
423   }
424   
425   /**'
426    * Returns the Score's key signature 
427    * The number of sharps (+) or flats (-)
428    * @return int key signature
429    */
430   public int getKeySignature(){
431     return this.keySignature;
432   }
433   
434   /**
435    * Specifies the Score's key signature 
436    * The number of sharps (+) or flats (-)
437    * @param int key signature
438    */
439   public void setKeySignature(int newSig){
440     this.keySignature = newSig;
441   }
442   
443   /**
444    * Returns the Score's key quality 
445    * 0 is Major, 1 is minor
446    * @return int key quality
447    */
448   public int getKeyQuality(){
449     return this.keyQuality;
450   }
451   
452   /**
453    * Specifies the Score's key quality 
454    * 0 is Major, 1 is minor
455    * @param int key quality (modality)
456    */
457   public void setKeyQuality(int newQual){
458     this.keyQuality = newQual;
459   }
460   
461   /**
462    * Returns the Score's time signature numerator 
463    * @return int time signature numerator
464    */
465   public int getNumerator(){
466     return this.numerator;
467   }
468   
469   /**
470    * Specifies the Score's time signature numerator 
471    * @param int time signature numerator
472    */
473   public void setNumerator(int num){
474     this.numerator = num;
475   }
476   
477   /**
478    * Returns the Score's time signature denominator 
479    * @return int time signature denominator
480    */
481   public int getDenominator(){
482     return this.denominator;
483   }
484   
485   /**
486    * Specifies the Score's time signature denominator
487    * @param int time signature denominator
488    */
489   public void setDenominator(int dem){
490     this.denominator= dem;
491   }
492 
493   /**
494    * Make a copy of this Score object
495    * @return Score - return a new Score Object
496    */
497   public Score copy() {
498     Score newScore = new Score(title + " copy");
499     newScore.setTempo(this.tempo);
500     newScore.setVolume(this.volume);
501     Enumeration enum = this.partList.elements();
502     while(enum.hasMoreElements()){
503       Part oldPart = (Part) enum.nextElement();
504       newScore.addPart((Part) oldPart.copy());
505     }
506     return (Score)newScore;
507   }
508 
509     public Score copy(final double startTime, final double endTime) {
510         Score score = this.copy();
511         score.removeAllParts();
512         int scoresize = this.size();
513         for (int i = 0; i < scoresize; i++) {
514             score.addPart(this.getPart(i).copy(startTime, endTime));
515         }
516         return score;
517     }
518   
519   /**
520    * Return the beat where score ends. Where it's last Part ends.
521    * @return double the Parts endTime
522    */
523   public double getEndTime(){    
524     double endTime = 0.0;
525     Enumeration enum = this.partList.elements();
526     while(enum.hasMoreElements()){
527       Part nextPart = (Part)enum.nextElement();
528       double partEnd = nextPart.getEndTime();
529       if (partEnd > endTime) endTime = partEnd;
530     }
531     return endTime;
532   }  
533     
534     
535   /**
536    * Print the titles of all tracks to stdout
537    */
538   public String toString(){
539     String scoreData = new String("***** jMusic SCORE: '" + title + 
540       "' contains " + this.size() + " parts. ****" + '\n');
541     scoreData += "Score Tempo = " + this.tempo + " bpm" +'\n';
542     Enumeration enum = partList.elements();
543     while(enum.hasMoreElements()){
544       Part part = (Part) enum.nextElement();
545       scoreData = scoreData + part.toString() + '\n';
546     }
547     return scoreData;
548   }
549   
550   /**
551   * Empty removes all elements in the vector
552   */
553   public void empty(){
554     this.empty(false);
555   }
556         
557         /**
558   * Empty removes all elements in the vector.
559         * @param nullObjects If ture this sets all jMusic data objects to null
560         *      priot to removing. This facilitates garbage collection.
561   */
562   public void empty(boolean nullObjects){
563     if(nullObjects) {
564                     Enumeration enum = getPartList().elements();
565                     while(enum.hasMoreElements()){
566                         Part part = (Part) enum.nextElement();
567                         Enumeration enum2 = part.getPhraseList().elements();
568                         while(enum2.hasMoreElements()){
569                             Phrase phrase = (Phrase) enum2.nextElement();
570                             Enumeration enum3 = part.getPhraseList().elements();
571                             while(enum3.hasMoreElements()){
572                                 Note note = (Note) enum3.nextElement();
573                                 note = null;
574                             }
575                             phrase = null;
576                         }
577                         part = null;
578                     }
579                 }
580                 partList.removeAllElements();
581   }
582          
583         /**
584    * Get the number of Parts in this score
585    * @return int  The number of parts
586    */
587   public int length(){
588             return size();
589         }
590                                            
591   /**
592    * Get the number of Parts in this score
593    * @return int  length - the number of parts
594    */
595   public int size(){
596     return(partList.size());
597   }
598     
599     /**
600    * Get the number of Parts in this score
601    * @return int  length - the number of parts
602    */
603   public int getSize(){
604     return(partList.size());
605   }
606     
607     /**
608    * Remove any empty Parts or phrases from the Score.
609    */
610    public void clean() {
611              Enumeration enum = getPartList().elements();
612              while(enum.hasMoreElements()){
613                  Part part = (Part) enum.nextElement();
614                  // pass on the part to have phases cleaned
615                 part.clean();
616                 // check if part is empty
617                  if (part.getPhraseList().size() == 0) {
618                      this.removePart(part);
619                  }
620              }
621   }
622     
623     /**
624    * Return the value of the highest note in the Score.
625      */
626     public int getHighestPitch() {
627         int max = 0;
628         Enumeration enum = getPartList().elements();
629     while(enum.hasMoreElements()){
630       Part part = (Part) enum.nextElement();
631             if(part.getHighestPitch() > max) max = part.getHighestPitch();
632         }
633         return max;
634     }
635     
636     /**
637    * Return the value of the lowest note in the Score.
638      */
639     public int getLowestPitch() {
640         int min = 127;
641         Enumeration enum = getPartList().elements();
642     while(enum.hasMoreElements()){
643       Part part = (Part) enum.nextElement();
644             if(part.getLowestPitch() < min) min = part.getLowestPitch();
645         }
646         return min;
647     }
648     
649     /**
650    * Return the value of the longest rhythm value in the Score.
651      */
652     public double getLongestRhythmValue() {
653         double max = 0.0;
654         Enumeration enum = getPartList().elements();
655     while(enum.hasMoreElements()){
656       Part part = (Part) enum.nextElement();
657             if(part.getLongestRhythmValue() > max) max = part.getLongestRhythmValue();
658         }
659         return max;
660     }
661     
662     /**
663    * Return the value of the shortest rhythm value in the Score.
664      */
665     public double getShortestRhythmValue() {
666         double min = 1000.0;
667         Enumeration enum = getPartList().elements();
668     while(enum.hasMoreElements()){
669       Part part = (Part) enum.nextElement();
670             if(part.getShortestRhythmValue() < min) min = part.getShortestRhythmValue();
671         }
672         return min;
673     }
674 
675   /**
676   * Determine the pan position for all notes in this Score.
677    * @param double the phrase's pan setting
678    */
679   public void setPan(double pan){
680     Enumeration enum = partList.elements();
681     while(enum.hasMoreElements()){
682       Part part = (Part) enum.nextElement();
683       part.setPan(pan);
684     }
685   }
686         
687         /**
688         * Generates and returns a new empty part 
689         * and adds it to the score.
690         */
691         public Part createPart() {
692             Part p = new Part();
693             this.addPart(p);
694             return p;
695         }
696 }