javauis/mmapi_qt/baseline/javasrc/com/nokia/microedition/media/tone/ToneSequence.java
changeset 23 98ccebc37403
equal deleted inserted replaced
21:2a9601315dfc 23:98ccebc37403
       
     1 /*
       
     2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  This class represents tone sequence for tone to midi conversion
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.microedition.media.tone;
       
    20 
       
    21 import javax.microedition.media.control.ToneControl;
       
    22 import java.io.ByteArrayInputStream;
       
    23 import java.io.IOException;
       
    24 import java.util.Stack;
       
    25 import com.nokia.mj.impl.utils.Logger;
       
    26 
       
    27 
       
    28 /**
       
    29  * This class represents tone sequence for tone to midi conversion
       
    30  */
       
    31 public class ToneSequence
       
    32 {
       
    33     // MEMBER DATA
       
    34 
       
    35     /* Hold original tone sequence bytes */
       
    36     private byte[] iToneSequence;
       
    37 
       
    38     /* Holds the new tone sequence converted to MIDI */
       
    39     private MidiSequence iMidiSequence;
       
    40 
       
    41     /* Event list used to hold tone event processors */
       
    42     private EventList iEventList;
       
    43 
       
    44     ToneSequence(byte[] aSequence)
       
    45     {
       
    46         iToneSequence = aSequence;
       
    47         iMidiSequence = new MidiSequence(MidiToneConstants.MIDI_TONE_CHANNEL,
       
    48                                          MidiToneConstants.MIDI_TONE_INSTRUMENT);
       
    49         iEventList = new EventList(iToneSequence, iMidiSequence);
       
    50     }
       
    51 
       
    52     public void process()
       
    53     {
       
    54         // Reset static base class variables of events before processing.
       
    55         iEventList.reset();
       
    56 
       
    57         // Check input; tone sequence must be even length
       
    58         // ie. multiple of event size
       
    59         if ((iToneSequence.length % Event.EVENT_SIZE) != 0)
       
    60         {
       
    61             throw new IllegalArgumentException(
       
    62                 "Illegal sequence, tone sequence must be multiple of single tone event size (2)");
       
    63         }
       
    64 
       
    65         // Validate header bytes
       
    66 
       
    67         // Next check that have correct VERSION and possibly
       
    68         // VERSION and RESOLUTION.
       
    69         int checkPos = 0;
       
    70 
       
    71         // First two bytes must belong to VERSION
       
    72         if (iToneSequence[ checkPos ] != ToneControl.VERSION ||
       
    73                 iToneSequence[ checkPos + 1 ] !=
       
    74                 MidiToneConstants.TONE_SEQUENCE_SUPPORTED_VERSION)
       
    75         {
       
    76             throw new IllegalArgumentException(
       
    77                 "Illegal sequence, first two bytes must belong to version");
       
    78         }
       
    79 
       
    80         // Next two may be TEMPO or RESOLUTION
       
    81         checkPos += Event.EVENT_SIZE;
       
    82 
       
    83         if (iToneSequence[ checkPos ] == ToneControl.TEMPO)
       
    84         {
       
    85             iMidiSequence.setTempo(iToneSequence[ checkPos + 1 ]);
       
    86             checkPos += Event.EVENT_SIZE;
       
    87         }
       
    88 
       
    89         // Continue checking RESOLUTION
       
    90         if (iToneSequence[ checkPos ] == ToneControl.RESOLUTION)
       
    91         {
       
    92             iMidiSequence.setResolution(iToneSequence[ checkPos + 1 ]);
       
    93             checkPos += Event.EVENT_SIZE;
       
    94         }
       
    95 
       
    96         // Validate rest of the sequence
       
    97 
       
    98         int count = 0; // Offset to new position in tone sequence. >= 0
       
    99         while (checkPos < iToneSequence.length)
       
   100         {
       
   101             count = iEventList.validate(checkPos);
       
   102             checkPos += count;
       
   103             if (count == 0)
       
   104             {
       
   105                 // if end of tone sequence is reached, zero is
       
   106                 // OK. Otherwise this indicates error
       
   107                 if (checkPos != iToneSequence.length)
       
   108                 {
       
   109                     throw new IllegalArgumentException(
       
   110                         "Validation failed, sequence corrupted");
       
   111                 }
       
   112                 break;
       
   113             }
       
   114         }
       
   115 
       
   116         // Find start of sequence
       
   117         int position = 0; // current position on tone sequence
       
   118 
       
   119         for (int i = iToneSequence.length - Event.EVENT_SIZE;
       
   120                 i >= 0;
       
   121                 i -= Event.EVENT_SIZE)
       
   122         {
       
   123             // There cannot be any lower value command bytes in tone sequence
       
   124             // than REPEAT
       
   125             if (iToneSequence[ i ] < ToneControl.REPEAT)
       
   126             {
       
   127                 throw new IllegalArgumentException(
       
   128                     "Illegal sequence, lower value command than ToneControl.REPEAT found");
       
   129             }
       
   130 
       
   131             if (iToneSequence[ i ] < ToneControl.SILENCE &&
       
   132                     iToneSequence[ i ] != ToneControl.PLAY_BLOCK &&
       
   133                     iToneSequence[ i ] != ToneControl.SET_VOLUME &&
       
   134                     iToneSequence[ i ] != ToneControl.REPEAT)
       
   135             {
       
   136                 position = i + Event.EVENT_SIZE;
       
   137                 // stop the for loop
       
   138                 break;
       
   139             }
       
   140         }
       
   141 
       
   142         // No start position found
       
   143         if (position < Event.EVENT_SIZE)
       
   144         {
       
   145             throw new IllegalArgumentException(
       
   146                 "Illegal sequence, no start position found");
       
   147         }
       
   148 
       
   149         count = 0; // offset to new position in tone sequence. +/-
       
   150         try
       
   151         {
       
   152             while (position > 0 && position < iToneSequence.length)
       
   153             {
       
   154                 count = iEventList.advance(position);
       
   155                 position += count;
       
   156                 if (count == 0)
       
   157                 {
       
   158                     // if end of tone sequence is reached, zero is
       
   159                     // OK. Otherwise this indicates error
       
   160                     if (position != iToneSequence.length)
       
   161                     {
       
   162                         throw new IllegalArgumentException(
       
   163                             "Validation failed, sequence corrupted");
       
   164                     }
       
   165                     break;
       
   166                 }
       
   167             }
       
   168         }
       
   169         catch (MidiSequenceException mse)
       
   170         {
       
   171             // This exception indicates that we have reached the maximum
       
   172             // midi sequence length and thus must stop processing. Currently
       
   173             // processed midi sequence is however available by getStream.
       
   174             // So no action is needed here.
       
   175             Logger.WLOG(Logger.EJavaMMAPI,
       
   176                         "MMA: ToneSequence: MIDI maximum lenght reached.");
       
   177         }
       
   178     }
       
   179 
       
   180     public ByteArrayInputStream getStream() throws IOException
       
   181     {
       
   182         return iMidiSequence.getStream();
       
   183     }
       
   184 
       
   185     public byte[] getByteArray() throws IOException
       
   186     {
       
   187         return iMidiSequence.getByteArray();
       
   188     }
       
   189 
       
   190     /**
       
   191      * Get duration of tone sequence
       
   192      */
       
   193     public long getDuration()
       
   194     {
       
   195         return iMidiSequence.getCumulativeDuration();
       
   196     }
       
   197 } // end of class
       
   198