в играх создает более насыщенную-
Воспроизведение звуков в играх создает более насыщенную- атмосферу. Хорошая звуковая дорожка к игре - это 30-40% успеха! Но, к сожалению, в мобильных играх, нет возможности воспроизведения мощной полноценной звуковой дорожки, как в компьютерных или приставочных играх, в виду ограничения системных ресурсов телефона. Поэтому, в основном, все звучание в играх сводится к воспроизведению так называемых тональных звуков. Каждый тональный звук соответствует определенной ноте, выстроив необходимую последовательность нот для воспроизведения можно получить определенную звуковую дорожку.
В профиле MIDP 1.0 возможность работы со звуком отсутствует, и все строится на использовании классов, предоставляемых производителями мобильных телефонов. В профиле MIDP 2.0 такая возможность имеется, поскольку появилась мобильная мультимедиа библиотека (MMAPI), разработаная экспертной группой, в состав которой входят известные компании:
Nokia (Specification Lead); Aplix Corporation; Beatnik. Inc.; France Telecom; Insignia Solutions; Mitsubishi Electric Corp.; Motorola; Netdecisions Holdings United; NTT DoCoMo, Inc.;
Openwave Systems Inc.; PacketVideo Corporation; Philips; Siemens AG ICM MP TI; Smart Fusion; Sun Microsystems, Inc.; Symbian Ltd; Texas Instruments Inc.; Vodafone; Yamaha Corporation; Zucotto Wireless.
На данный момент существуют две мобильные мультимедиа-библиотеки, различающиеся по своему назначению и спецификации, это:
Mobile Media API - предназначена для работы с устройствами имеющими боле мощные системные ресурсы. Это, как правило, карманные портативные устройства; MIDP 2.0 Media API - эта библиотека направлена на поддержку мобильных устройств с ограниченными ресурсами.
В этой главе будет представлена мобильная мультимедиа библиотека MIDP 2.0 Media API, которая используется при программировании звука в приложениях написанных под профиль MIDP 2.0. Работа со звуком строится по принципу блочной конструкции состоящей из трех ключевых блоков:
Менеджер - это основной диспетчер, при помощи которого создаются все проигрыватели. Также менеджер имеет возможность в воспроизведении простых тональных звуков на телефоне. Менеджер в профиле MIDP 2.0 представлен классом Manager; Проигрыватель - осуществляет непосредственное воспроизведение звуков и представлен интерфейсом Player
Bee взаимодействие построено на использовании нескольких интерфейсов и класса Manager, содержащихся в библиотеке MIDP 2.0 Media API, которая состоит из двух пакетов:
javax.microedition.media; javax.microedition.media.control.
Эти два пакета содержат ряд интерфейсов и всего один класс Manager. Рассмотрим подробно оба пакета библиотеки MIDP 2.0 Media API, давая попутно краткую характеристику каждому интерфейсу, классу Manager и всем имеющимся методам. А потом, на основе полученного материала, создадим несколько примеров исходного кода, иллюстрирующих мoдель работы со звуком.
Пакет javax.microedition.media
Пакет javax.microedition.media необходим для работы со звуком и содержит четыре основных интерфейса и один класс, на базе которых и происходит воспроизведение звуков в телефоне.
Интерфейс Control
Интерфейс Control - это самый главный интерфейс, с его помощью осуществляется контроль над всеми имеющимися ресурсами, также от этого интерфейса наследуются еще два интерфейса ToneControl и VolumeControl.
Интерфейс Controllable
С помощью интерфейса Controllable можно получить управление над воспроизведением, посредством использования двух методов:
Control getControl (String controlType) - определяет тип управления; Control[] getControls () - получает управление.
Интерфейс Player
Интерфейс Player наследуется от интерфейса Controllable и необходим для реализации процесса воспроизведения звуковых данных на основе формирования проигрывателей. Проигрыватели создаются методом createPlayer () класса Manager, например:
Player player1 = Manager.createPlayer();
После создания проигрывателя можно производить воспроизведения звука, для этого необходимо воспользоваться методами интерфейса Player.
Методы интерфейса Player
void addPlayerListener(PlayerListener playerListener)-осуществляет обработку событий от определенного проигрывателя; void close () — закрывает проигрыватель; void deallocate () - освобождает ресурс, занятый проигрывателем; String getContentType () - получает тип звуковых данных воспроизводимых проигрывателем; long getDuration () — получает размер звукового файла; long getMediaTime () - получает время воспроизведения звуковых данных; int getState() — определяет состояние проигрывателя; void removePlayerListener(PlayerListener playerListener) — удаляет установленный обработчик событий; void setLoopCount (int count) - устанавливает цикличное воспроизведение звуковых данных; long setMediaTime(long now) - устанавливает время воспроизведения; void start () - дает команду на воспроизведение; void stop () - останавливает воспроизведение.
Большинство методов направленно на работу со звуковыми данными, позже в разделе 9.3 мы разберем подробнее работу с методами интерфейса Player.
Интерфейс PlayerListener
Интерфейс PlayerListener позволяет осуществлять обработку событий полученных от проигрывателя. Помните в главе 5 мы разбирали работу интерфейса CommandListener? Интерфейс PlayerListener функционирует почти по такой же схеме, но ориентирован на работу с проигрывателем. В составе интерфейса PlayerListener .имеется всего один метод:
void playerUpdate (Player player, String event, Object eventData) — обновляет состояние проигрывателя.
C помощью констант интерфейса Player в методе playerUpdate (), нужно задавать тип необходимых событий в параметрах eventData и event:
static String CLOSED - уведомляет о закрытии проигрывателя; static String DEVICE_AVAILABLE - уведомляет о доступности проигрывателя; static String DEVICE_UNAVAILABLE - уведомляет о недоступности проигрывателя; static String DURATIONJJPDATED - обновляет состояние; static String END_OF_MEDIA - уведомляет о конце воспроизведения данных проигрывателем; static String ERROR - уведомляет об ошибке; static String STARTED - уведомляет о начале работы проигрывателя; static String STOPPED - уведомляет о конце работы проигрывателя; static String VOLUME_CHANGED - уведомляет о выборе громкости для воспроизведения.
Класс Manager
Класс Manager создает проигрыватель для воспроизведения звуков, а также отслеживает доступные протоколы звуковых данных, с помощью нескольких методов.
static Player createPlayer(InputStream stream, String type) - создает проигрыватель для воспроизведения звуковых данных из потока; static Player createPlayer(String locator) - создает проигрыватель для воспроизведения звуковых данных из определенного файла; static String[] getSupportedProtocols(String content_type) - возвращает список доступных протоколов для мобильного устройства; static void playTone(int note, int duration, int volume) -воспроизводит различные тональные звуки.
Пакет javax.microedition.media.control
Пакет javox.microedition.media.control небольшой по своему составу и производит контроль над процессами, связанными с воспроизведением и регулировкой звука. В разделе 9.4 этой главы очень подробно рассматривается схема контроля.
Интерфейс ToneControl
С помощью интерфейса ToneControl происходит настройка и построение блока тональных звуков для воспроизведения. Это достигается путем использования метода void setSequence (byte [ ] sequence), который устанавливает тональные звуки для воспроизведения и набора следующих констант:
static byte BLOCK_END - конец блока воспроизведения; static byte BLOCK_START - стартовая позиция в блоке; static byte C4 - нота До; static byte PLAY_BLOCK - воспроизвести блок; static byte REPEAT - повторить воспроизведение блока; static byte SET_VOLUME - установить громкость; static byte SILENCE - без звука; static byte TEMPO — темп или скорость воспроизведения; static byte VERSION - версия атрибута воспроизведения. С помощью перечисленных констант производится настройка блока тональных звуков для воспроизведения, о которых мы поговорим подробно в разделе 9.4.
Интерфейс VolumeControl
Интерфейс VolumeControl имеет методы, на основе которых можно реализовать управление громкостью воспроизведения:
int getLevel() - возвращает текущий уровень громкости; boolean isMutedf) - определяет состояние сигнала; int setLevel(int level) -устанавливает уровень громкости. Значение может находиться в пределах от 0 до 100; void setMute (boolean mute) - устанавливает состояние сигнала.
Сейчас мы вкратце рассмотрели имеющиеся интерфейсы, классы, методы и константы двух пакетов javax.microedition.media и javax.microedition.media.control. Теперь давайте подытожим все полученную информацию и рассмотрим примеры, иллюстрирующие работу со звуком в мобильных телефонах.
Воспроизведение wav-файлов
Воспроизведение wav-фа.йлов в телефоне задача не сложная. Wav-файл должен быть размещен в каталоге создаваемого приложения. Если вы используете J2ME Wireless Toolkit 2.1, то расположите wav-файл в папке res. Впоследствии, после компиляции и установки программы, wav-файл будет находиться в JAR- архиве, и доступен для воспроизведения.
Для того чтобы воспроизвести необходимый wav-файл создается объект класса Inputstream для связывания потока данных с ресурсом, а именно wav-файлом,например:
Inputstream input = getClassf).getResourceAsStream(«файл.wav»);
Затем создается проигрыватель:
Player player = Manager.createPlayer(input,«audio/X-wav»);
Проигрыватель формируется с помощью метода createPlayer() класса Manager. Количество создаваемых проигрывателей регламентируется только системными ресурсами телефона. После чего используется метод start() для воспроизведения wav-файла.
В листинге 9.1 вы найдете пример исходного кода, в котором происходит загрузка и воспроизведение wav-файла из JAR-архива. В примере используется класс Form, с помощью которого создается пустой экран, и добавляются две команды: выход из приложения и воспроизведение wav-файла. Основные действия разворачиваются в методе WavPlay (), где создается проигрыватель и воспроизводится wav-файл. Обратите также внимание на подключаемые пакеты.
/**
листинг 9.1.
класс WavMIDlet воспроизводит wav-файл
*/
import javax.microedition.Icdui.*;
import javax.microedition.midlet.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
public class WavMIDlet
extends MIDlet implements CommandListener
{
// команда выхода
private Command
exitMidlet = new Command("Выход", Command.EXIT, 0);
// команда воспроизведения
private Command
pi = new Command("Играть", Command.OK, 1);
// объект mydisplay представляет экран телефона
private Display mydisplay;
public WavMIDlet()
{
mydisplay = Display.getDisplay(this);
}
public void startApp()
{
Form Is = new Form("Воспроизведение wav");
// добавляем команду выхода
ls.addCommand(exitMidlet);
// добавляем команду воспроизведения
ls.addCommand(pl);
ls.setCommandListener(this);
// отражаем текущий дисплей
mydisplay.setCurrent(Is);
}
private void WawPlay()
{
try {
// ищем ресурс с именем melod.wav
InputStream
input =getClass().getResourceAsStream("melod.wav");
// создаем проигрыватель
Player player = Manager.createPlayer(input, "audio/X-wav");
// воспроизводим player.start();
}
catch (lOException zxz) {} catch (MediaException zmz) {}
}
public void pauseApp() {}
public void destroyApp(boolean unconditional){}
public void commandAction(Command c, Displayable d)
{
if (c == exitMidlet)
{
destroyApp(false); notifyDestroyed() ;
}
if (c = = pi) {
WawPlay();
}
}
}
Воспроизведение тональных звуков
При создании звукового сопровождения к играм и приложениям в основном используются так называемые тональные звуки, генерируемые телефоном. Мобильные телефоны ограничены в системных ресурсах, поэтому воспроизведение wav, mp3 файлов не всегда возможно.
Воспроизведение тональных звуков происходит примерно тем же способом, что и воспроизведение wav-файлов, рассмотренное в предыдущем разделе. Создание тональных звуков строится на основе секвенсора, используемого музыкантами. То есть, в вашем распоряжении имеются семь нот, которые могут быть сыграны в любой тональности. Указав определенную последовательность нот в заданном массиве данных, вы сможете их впоследствии последовательно воспроизвести. В принципе, аналогичные действия можно произвести в любом телефоне, где в музыкальном редакторе вы выстраиваете некую последовательность определенных Символов, обозначающих ноты. Указав нужную последовательность нот, вы получаете готовую мелодию, созданную при помощи тональных звуков.
Перейдем к практике. Первым делом необходимо создать те самые семь нот. В классе ToneControl пакета javax.microedition.media.control.*, доступна константа С4, которая по своему звучанию соответствует ноте «До». Для того чтобы создать, например ноту Ре, можно воспользоваться следующей конструкцией кода:
byte Re = (byte)(ToneControl.C4+1);
Для создания последующей ноты Ми нужно прибавить к ноте До (то есть С4), число два и так далее. Когда закончатся все семь нот, то вы переходите к следующей октаве, что и предопределяет разные тональности звукового сопровождения. Всего можно использовать значение от 0 до 127.
Затем создается массив данных, можно назвать его секвенсором, в котором указывается последовательность нот. Синтаксис, используемый в секвенсоре, строго определен, и его необходимо правильно использовать. Например, имеется следующий массив данных, характеризующийся как секвенсор:
byte[] Nota = {...};
В этом массиве данных первой строкой кода должно идти указание версии используемого атрибута.
ToneControl.VERSION,1,
Затем задается скорость воспроизведения с помощью целочисленного значения, которое может варьироваться от 5 до 127. Например:
ToneControl.TEMPO,30,
Далее необходимо дать команду, указывающую начало блока последовательности нот для воспроизведения, например:
ToneControl.BLOCK_START, 0,
И только после этого идет последовательность нот. Между нотами ставится обязательно длина ноты обычно заданная переменной, и ее диапазон может быть от 2 до 16. Например:
byte d = 4;
Re,d,Mi,d,Re,d,
Между воспроизведением нот можно использовать паузы для создания выразительной мелодии. Пауза задается с помощью константы SELENCE, например:
byte stop = ToneControl.SELENCE;
byte d = 4;
Тогда последовательность нот может быть следующей:
Re,d,stop,d,Mi,d,stop,d,stop,d,Re,d,
После того как вы задали всю последовательность нот, необходимо четко указать конец блока с помощью константы BLOCK_END следующим образом:
ToneControl.BLOCK_END, 0,
На каждую константу BLOCK_START, должна присутствовать константа BLOCK_END. Иначе возникнет ошибка при компиляции.
В конце нужно воспользоваться константой PLAY_BLOCK для воспроизведения блока последовательности нот. После этого созданный секвенсор можно использовать для воспроизведения проигрывателем тональных звуков. Посмотрите на листинг 9.2, где показана демонстрационная программа, воспроизводящая все семь нот одной октавы.
/ * *
листинг 9.2
класс TonMIDlet воспроизводит тональные звуки
*/
import javax.microedition.Icdui.*;
import javax.microedition.midlet.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
public class TonMIDlet
extends MIDlet implements CommandListener
// команда выхода
private Command
exitMidlet = new Command("Выход",Command.EXIT, 0);
// команда воспроизведения
private Command pi = new
Command("Играть", Command.OK, 1);
// объект mydisplay представляет экран телефона
private Display mydisplay;
public TonMIDlet()
{
mydisplay = Display.getDisplay(this);
}
public void startApp()
Form Is = new Form("Тональные звуки");
// добавляем команду выхода
ls.addCommand(exitMidlet);
// добавляем команду воспроизведения
ls.addCoiranand(pl);
ls.setCommandListener(this);
// отражаем текущий дисплей
my.display. setCurrent (Is) ;
}
private void TonPlay() {
// нота До
byte Do = ToneControl.C4;,
// нота Ре
byte Re = (byte)(ToneControl.C4 + 1);
// нота Ми
byte Mi = (byte)(ToneControl.C4 + 2) ;
// нота Фа
byte Fa = (byte)(ToneControl.C4 + 3);
// нота Соль
byte So = (byte)(ToneControl.C4 + 4);
// нота Ля
byte Lj = (byte)(ToneControl.C4 + 5);
// нота Си
byte Si = (byte)(ToneControl.C4 + 6);
// пауза
byte stop = ToneControl.SILENCE;
// скорость воспроизведения тональных звуков
byte speed = 30;
// продолжительность воспроизведения ноты
byte pr = 4;
// секвенсор
byte[] Nota = {
// атрибут, задающий номер версии
ToneControl.VERSION, 1,
// скорость воспроизведения
ToneControl.TEMPO, speed,
// начало блока
ToneControl.BLOCK_START, 0,
// последовательность нот для воспроизведения
Do,pr,stop,pr,Re,pr,stop,pr,Mi,pr,stop,pr,
Fa,pr,stop,pr,So,pr,stop,pr,Lj,pr,stop,pr,Si,pr,
// конец блока
ToneControl.BLOCK_END, 0,
// воспроизведение блока
ToneControl.PLAY_BLOCK, 0,
} ;
// воспроизводим тональные звуки из секвенсора
try{
Player player =
Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
player.realize();
ToneControl toncontrl = (ToneControl)player.getControl(«ToneControl»);
toncontrl.setSequence(Nota);
player.start();
}
catch (IOException zxz){}
catch (MediaException zmz){}
}
public void pauseApp() {}
public void destroyApp(boolean unconditional){}
public void commandAction(Command c, Displayable d)
{
if (c = = exitMidlet)
{
destroyApp(false);
notifyDestroyed();
}
if (c == pi)
{
TonPlay();
}
}
}
В основе программы из листинга 9.2 лежит модель, используемая в предыдущем разделе при .воспроизведении wav-файла. В классе TonMIDlet создается пустая форма классом Form и назначаются две команды: выход из программы и воспроизведение тональных звуков. При нажатии на кнопку Играть, задействуется метод TonPlay (), где создаются ноты, секвенсор, после чего происходит воспроизведение последовательности нот.