/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.midp.player;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.media.*;
import malik.emulator.fileformats.sound.sampled.wavelib.*;
import malik.emulator.fileformats.sound.synthetic.midilib.*;
import malik.emulator.io.j2me.*;
import malik.emulator.media.sound.*;
public class SupportedPlayerFormats extends Object
implements VirtualPlayerManager
{
private static final String CONTENT_TYPE_AUDIO_MIDI = "audio/midi";
private static final String CONTENT_TYPE_AUDIO_WAVE = "audio/x-wav";
private static final String PROTOCOL_SIGNATURE = "://";
private static final String PROTOCOL_RESOURCE = "resource";
private static final String PROTOCOL_RESOURCE_SIGNATURE =
PROTOCOL_RESOURCE + PROTOCOL_SIGNATURE;
private static final class NoteOffTask extends Scheduler.Task
{
private int message;
private SoundPlayerMessaged generator;
NoteOffTask(SoundPlayerMessaged generator, int message)
{
this.message = message;
this.generator = generator;
}
public void run()
{
generator.sendMessage(message);
}
}
public static int midpVolumeToDeviceVolume(int volume)
{
return volume < 0 ? 0 : (volume >= 100 ? 127 : (volume * 127) / 100);
}
public static int midpVolumeToMIDPVolume(int volume)
{
return volume < 0 ? 0 : (volume > 100 ? 100 : volume);
}
public static int deviceVolumeToMIDPVolume(int volume)
{
return volume < 0 ? 0 : (volume >= 127 ? 100 : (volume * 100) / 127);
}
private static long continueReadSignature(long signature, InputStream stream, int bytes)
throws IOException
{
int i;
for(i = bytes; i-- > 0; )
{
signature = (signature << 8) | (long) stream.read();
}
return signature;
}
private String[] supportedContentTypes;
private String[] supportedProtocols;
private String[] emptyList;
private SoundPlayerMessaged toneGenerator;
public SupportedPlayerFormats()
{
SoundPlayerMessaged generator;
try
{
generator = SoundPlayerSynthetic.open();
}
catch(SoundPlayerException e)
{
generator = null;
}
this.supportedContentTypes = new String[] {
CONTENT_TYPE_AUDIO_MIDI, CONTENT_TYPE_AUDIO_WAVE
};
this.supportedProtocols = new String[] {
PROTOCOL_RESOURCE
};
this.emptyList = new String[0];
this.toneGenerator = generator;
}
public void playTone(int note, int duration, int volume)
throws MediaException
{
int msg;
SoundPlayerMessaged generator;
if(note < 0x00 || note > 0x7f)
{
throw new IllegalArgumentException("Manager.playTone: " +
"параметр note выходит из диапазона.");
}
if(duration <= 0)
{
throw new IllegalArgumentException("Manager.playTone: " +
"параметр duration может быть только положительным.");
}
if((generator = toneGenerator) == null)
{
throw new MediaException("Manager.playTone: " +
"системе не хватает памяти для создания нового MIDI-проигрывателя или " +
"система не поддерживает стандарт MIDI.");
}
generator.sendMessage((msg = 0x900000 | (note << 8)) | midpVolumeToDeviceVolume(volume));
Scheduler.schedule(new NoteOffTask(generator, msg), (long) duration, Scheduler.MONOPOLY);
}
public String[] getSupportedContentTypes(String protocol)
{
int i;
String[] list;
String[] result = emptyList;
if(protocol != null)
{
for(i = (list = supportedProtocols).length; i-- > 0; )
{
if(protocol.equalsIgnoreCase(list[i]))
{
result = supportedContentTypes;
break;
}
}
} else
{
result = supportedContentTypes;
}
Array.copy(result, 0, result = new String[i = result.length], 0, i);
return result;
}
public String[] getSupportedProtocols(String type)
{
int i;
String[] list;
String[] result = emptyList;
if(type != null)
{
for(i = (list = supportedContentTypes).length; i-- > 0; )
{
if(type.equalsIgnoreCase(list[i]))
{
result = supportedProtocols;
break;
}
}
} else
{
result = supportedProtocols;
}
Array.copy(result, 0, result = new String[i = result.length], 0, i);
return result;
}
public Player createPlayer(InputStream stream, String type)
throws IOException, MediaException
{
long signature;
ContentPlayer result;
if(stream == null)
{
throw new IllegalArgumentException("Manager.createPlayer: " +
"параметр stream равен нулевой ссылке.");
}
signature = continueReadSignature(0L, stream, 4);
if(type == null)
{
if(signature == WaveDecoder.RIFF_SIGNATURE)
{
result = new SampledPlayer(new WaveDecoder(), CONTENT_TYPE_AUDIO_WAVE);
}
else if(continueReadSignature(signature, stream, 4) == MIDIDecoder.MIDI_SIGNATURE)
{
result = new SyntheticPlayer(new MIDIDecoder(), CONTENT_TYPE_AUDIO_MIDI);
}
else
{
throw new MediaException("Manager.createPlayer: " +
"не удалось распознать тип содержимого.");
}
}
else if(signature == WaveDecoder.RIFF_SIGNATURE &&
CONTENT_TYPE_AUDIO_WAVE.equalsIgnoreCase(type))
{
result = new SampledPlayer(new WaveDecoder(), CONTENT_TYPE_AUDIO_WAVE);
}
else if(continueReadSignature(signature, stream, 4) == MIDIDecoder.MIDI_SIGNATURE &&
CONTENT_TYPE_AUDIO_MIDI.equalsIgnoreCase(type))
{
result = new SyntheticPlayer(new MIDIDecoder(), CONTENT_TYPE_AUDIO_MIDI);
}
else
{
throw new MediaException("Manager.createPlayer: " +
"неизвестный тип содержимого " + type);
}
result.getData(stream);
return result;
}
public Player createPlayer(String locator)
throws IOException, MediaException
{
int len;
InputStream stream;
if(locator == null)
{
throw new IllegalArgumentException("Manager.createPlayer: " +
"параметр locator равен нулевой ссылке.");
}
if(PROTOCOL_RESOURCE_SIGNATURE.regionMatches(true, 0, locator, 0,
len = PROTOCOL_RESOURCE_SIGNATURE.length()))
{
stream = getClass().getResourceAsStream(locator.substring(len - 1));
}
else
{
throw new ConnectionNotFoundException("Manager.createPlayer: " +
"протокол не поддерживается.");
}
if(stream == null)
{
throw new ConnectionNotFoundException("Manager.createPlayer: " +
"соединение " + locator + " не найдено.");
}
return createPlayer(stream, null);
}
}