/*
    Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
    и других спецификаций для функционирования компактных приложений на языке
    Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package malik.emulator.fileformats.sound.sampled.wave;

import java.io.*;
import malik.emulator.fileformats.*;
import malik.emulator.fileformats.sound.sampled.*;

public final class WaveEncoder extends Object implements SampledSoundEncoder
{
    public static final long SIGNATURE = 0x52494646L; /* RIFF */

    private static final int WAVE = 0x57415645; /* WAVE */
    private static final int FMT  = 0x666d7420; /* fmt  */
    private static final int DATA = 0x64617461; /* data */

    private int channels;
    private int frequency;
    private short[] samples;

    public WaveEncoder() {
    }

    public void saveToOutputStream(OutputStream stream) throws IOException {
        saveToDataStream(new ExtendedDataOutputStream(stream));
    }

    public void saveToDataStream(ExtendedDataOutputStream stream) throws IOException {
        int len;
        int soundChannels = channels;
        int soundFrequency = frequency;
        byte[] soundData;
        short[] soundSamples = samples;
        if(soundSamples == null)
        {
            throw new EmptyAdapterException("WaveEncoder.saveToOutputStream: кодер не содержит данные.");
        }
        soundData = new byte[(len = soundSamples.length) << 1];
        for(int pos = 0, i = 0; i < len; i++)
        {
            int sample = soundSamples[i];
            soundData[pos++] = (byte) sample;
            soundData[pos++] = (byte) (sample >> 8);
        }
        stream.writeInt((int) SIGNATURE);
        stream.writeIntLE((len <<= 1) + 0x24);
        stream.writeInt(WAVE);
        stream.writeInt(FMT);
        stream.writeIntLE(0x10);
        stream.writeShortLE(1);
        stream.writeShortLE(soundChannels);
        stream.writeIntLE(soundFrequency);
        stream.writeIntLE((soundFrequency * soundChannels) << 1);
        stream.writeShortLE(soundChannels << 1);
        stream.writeShortLE(16);
        stream.writeInt(DATA);
        stream.writeIntLE(len);
        stream.write(soundData);
    }

    public void clear() {
        channels = 0;
        frequency = 0;
        samples = null;
    }

    public void setSamples(int channels, int samplesPerSecond, short[] samples) throws InvalidDataFormatException, UnsupportedDataException {
        int len;
        if(samples == null)
        {
            throw new NullPointerException("WaveEncoder.setSamples: аргумент samples равен нулевой ссылке.");
        }
        if(channels < 1 || channels > 2 || samplesPerSecond <= 0 || samplesPerSecond > 0xffff)
        {
            throw new UnsupportedDataException("WaveEncoder.setSamples: неподдерживаемые данные.");
        }
        if((len = samples.length) % channels != 0)
        {
            throw new InvalidDataFormatException("WaveEncoder.setSamples: неправильный формат данных.");
        }
        Array.copy(samples, 0, samples = new short[len], 0, len);
        this.channels = channels;
        this.frequency = samplesPerSecond;
        this.samples = samples;
    }

    public boolean isEmpty() {
        return (channels | frequency) == 0 && samples == null;
    }
}
