예제 #1
0
    /**
     * Fully copy the remaining bytes of this (decoded PCM sound data samples) stream into the specified {@link OutputStream}, that is, fully decodes the rest of the sound and copies the decoded data into the {@link OutputStream}.
     * <p>
     * This method is simply a convenience wrapper for the following code: {@code copy(this, os)}, where {@code copy} is a method that would fully copy a stream into another.
     * <p>
     * This method <b>is blocking</b> and the MPEG decoding process <b>might take a long time, e.g. a few seconds for a sample music track</b>. You are encouraged to call this method e.g. from a background thread.
     * <p>
     * The exact layout of the PCM data produced by this stream is described in this class documentation.
     *
     * @param os The output stream in which to put the decoded raw PCM sound samples, must be non-null.
     * @return The number of <b>BYTES</b> that were written into the output steam. <b>This is different from the number of samples that were written.</b>
     * @
     */
    public int decodeFullyInto(BinaryWriter writer)
    {
        Debug.Assert(writer != null);
        if (index == -1)
        {
            return(0);
        }

        int remaining = soundData.samplesBuffer.Length - index;

        if (remaining > 0)
        {
            writer.Write(soundData.samplesBuffer, index, remaining);
        }

        int read = remaining;

        while (Mp3Decoder.decodeFrame(soundData))
        {
            writer.Write(soundData.samplesBuffer);
            read += soundData.samplesBuffer.Length;
            // Debug.WriteLine(read);
        }

        soundData.samplesBuffer = null;
        index = -1;
        return(read);
    }
예제 #2
0
 /**
  * Creates a new Sound, that will read from the specified encoded MPEG data stream.
  * <p>
  * This method will try to read the very beginning of the MPEG stream (i.e. 1 MPEG frame) to get its sampling frequency and various other metadata. <b>A stream containing no MPEG data frames/a zero duration MPEG data source will be considered as invalid and will throw {@link IOException}.</b>
  * <p>
  * This method will not read or decode the file fully, which means it doesn't block and is very fast (as opposed to {@link #decodeFullyInto(OutputStream)}; you probably don't need to execute this method in a specific background thread.
  * <p>It is only when reading from this stream that the decoding process will take place (as you read from the stream). <b>The decoding process is quite CPU-intensive, though, so you are encouraged to use a background thread/other multithreading techniques to read from the stream without blocking the whole application.</b>
  * <p>
  * The various metadata methods such as {@link #getSamplingFrequency()} and {@link #isStereo()} may be called as soon as this object is instantiated (i.e. may be called at any time during the object lifetime).
  * <p>
  * <b>The data layout is as follows (this is a contract that won't change):</b>
  * <br>The decoded PCM sound data is stored as a contiguous stream of 16-bit little-endian signed samples (2 bytes per sample).
  * <ul>
  * <li>If the sound is in stereo mode, then the samples will be interleaved, e.g. {@code left_sample_0 (2 bytes), right_sample_0 (2 bytes), left_sample_1 (2 bytes), right_sample_1 (2 bytes), ...}
  * <li>If the sound is in mono mode, then the samples will be contiguous, e.g. {@code sample_0 (2 bytes), sample_1 (2 bytes), ...}
  * </ul>
  * @param in The input stream from which to read the encoded MPEG data, must be non-null.
  * @
  */
 public Sound(BinaryReader reader)
 {
     Debug.Assert(reader != null);
     soundData = Mp3Decoder.init(reader);
     if (soundData == null)
     {
         throw new IOException("No MPEG data in the specified input stream!");
     }
 }
예제 #3
0
    /**
     * {@inheritDoc}
     * <p>
     * Refer to this class documentation for the decoded data layout.
     */
    public int read(byte[] b, int off, int len)
    {
        if (b == null)
        {
            throw new Exception();
        }
        else if (off < 0 || len < 0 || len > b.Length - off)
        {
            throw new Exception();
        }
        else if (len == 0)
        {
            return(0);
        }

        if (index == -1)
        {
            return(-1);
        }

        int len_ = len;

        while (len > 0)
        {
            if (index == soundData.samplesBuffer.Length)
            {
                if (!Mp3Decoder.decodeFrame(soundData))
                {
                    index = -1;
                    soundData.samplesBuffer = null;
                    return(len_ == len ? -1 : len_ - len);
                }

                index = 0;
            }

            int remaining = soundData.samplesBuffer.Length - index;
            if (remaining > 0)
            {
                if (remaining >= len)
                {
                    Array.Copy(soundData.samplesBuffer, index, b, off, len);
                    index += len;
                    return(len_);
                }

                Array.Copy(soundData.samplesBuffer, index, b, off, remaining);
                off  += remaining;
                len  -= remaining;
                index = soundData.samplesBuffer.Length;
            }
        }

        throw new Exception("Shouldn't happen (internal error)");
    }
예제 #4
0
    /**
     * {@inheritDoc}
     * <p>
     * Refer to this class documentation for the decoded data layout.
     */
    public int read()
    {
        if (index == -1)
        {
            return(-1);
        }
        if (index == soundData.samplesBuffer.Length)
        {
            if (!Mp3Decoder.decodeFrame(soundData))
            {
                index = -1;
                soundData.samplesBuffer = null;
                return(-1);
            }

            index = 1;
            return(soundData.samplesBuffer[0] & 0xFF);
        }

        return(soundData.samplesBuffer[index++] & 0xFF);
    }