Работа со звуком в Android (Пишем движок часть 7)

Ну вообще-то работа со звуком — это слишком громкое название для этой статьи. На самом деле, во время написания этой вот игры у меня возникла необходимость проигрывать фоновые мелодии и звуки нажатия на экран. Ну и полез я в справку по Android SDK. Ребята из гугла предлагают для таких целей использовать класс SoundPool. Однако у меня с ним почему-то не заладилось. То ли я справку читал не внимательно, то ли еще что, не знаю… И я решил накидать пару своих собственных небольших классов для решения этой не столь уж эпохальной проблемы. Вот собственно об этих классах мы сейчас и поговорим.

Начнем с того, что опишем небольшой класс mSoundTrack, который будет отвечать за проигрывание одного звука. На самом деле — это просто обертка для класса MediaPlayer. И вот его код:

package ru.davidmd.myengine;

import android.content.Context;
import android.media.MediaPlayer;

public class mSoundTrack {
	private MediaPlayer track;
	private boolean playable;
	private String name;

	/**
	 * Конструктор
	 *
	 * @param cont
	 *            - контекст
	 * @param resid
	 *            - идентификатор ресурса
	 * @param name
	 *            - имя трека
	 * @param looped
	 *            - зацикленность проигрывания
	 */
	public mSoundTrack(Context cont, int resid, String name, boolean looped) {
		this.playable = true;
		this.track = MediaPlayer.create(cont, resid);
		this.track.setLooping(looped);
		this.name = name;
	}

	/**
	 * запускает трек если в настройках mSettings есть звук
	 */
	public void start() {
		if (mSettings.isSound()) {
			if (!track.isPlaying())
				track.start();
		} else
			this.stop();
	}

	/**
	 * перезапускает звук независимо от того играется он в данный момент или нет
	 */
	public void forceStart() {
		if (mSettings.isSound()) {
			if (track.isPlaying()) {
				track.pause();
				track.seekTo(0);
				track.start();
			} else {
				track.start();
			}
		}
	}

	/**
	 * приостанавливает проигрывание звука! ВНИМАНИЕ!!! Не высвобождает память,
	 * не отсоединяется от потока... просто приостанавливает!
	 */
	public void stop() {
		if (track.isPlaying())
			track.pause();
	}

	/**
	 * перематывает трек на начало
	 */
	public void rewind() {
		this.stop();
		track.seekTo(0);
		this.start();
	}

	/**
	 * @return возвращает параметр playable
	 */
	public boolean isPlayable() {
		return playable;
	}

	/**
	 * @param playable
	 *            - истина, если трек должен играться при проигрывании ложь в
	 *            противном случае
	 */
	public void setPlayable(boolean playable) {
		this.playable = playable;
	}

	public String getName() {
		return name;
	}

}

Теперь посмотрим попристальнее, что тут к чему. Имеются целых три переменные, это track — экземпляр класса MediaPlayer, name — строка в которой мы храним имя трека и логическая переменная playable — которая отвечает за то можно ли воспроизводить данный конкретный звук или нет (для чего нам последняя будет понятно чуть позже).

Соответственно имеется конструктор с целой кучей параметров: Context cont, int resid, String name, boolean looped. По порядку: Context cont — контекст из которого мы получаем доступ к ресурсам программы, int resid — идентификатор ресурса с изображением (надеюсь этой теме я тоже посвящу как-нить отдельную статью) — две эти переменные отвечают за загрузку данных из ресурсов мы их уже использовали в классе mSimpleSprite. Дальше все гораздо проще — сначала строка с именем звука, а затем, булева переменная looped — которая отвечает за то, будет ли зациклено воспроизведение нашего трека. Ну а сам конструктор думаю в комментариях не нуждается.

Идем дальше какие методы у нас здесь имеются? Давайте по порядку: start() — метод который запускает воспроизведение звука. Если звук был приостановлен, тогда воспроизведение продолжается с места где звук остановили. Метод forceStart() отличается от предыдущего тем, что если звук в данный момент воспроизводится, то происходит перемотка на самое начало трека и звук воспроизводится с самого начала. Оба эти метода проверяют перед запуском включен ли звук в классе глобальных настроек приложения mSettings.

Следующий метод stop() — не знаю почему я назвал его «стоп», ведь на самом деле он просто приостанавливает воспроизведение звука. На самом деле думаю стоило так и назвать его pause 🙂 Но видно писал все это я глубокой ночью, так что претензии не принимаются :). Метод rewind() тоже не  содержит каких-то откровений и просто перематывает звук на начало. Два метода isPlayable() и setPlayable(boolean playable) соответственно проверяют и устанавливают для трека статус playable. Ну а метод getName() — просто возвращает имя трека. Вот и все что касается нашего трека. Итак у нашего проигрывателя есть треки, и мы легко можем их проиграть, приостановить или перемотать на начало. Казалось бы, для наших целей большего и не надо! Но нет, на самом деле в игре (а вы ведь не забыли что это все еще часть нашего игрового движка?) гораздо удобнее обладать каким-то общим средством для запуска и проигрывания звуков.

Таким средством станет наш следующий класс: mPlayer. Начну по привычке с его кода:

package ru.davidmd.myengine;

import java.util.ArrayList;

import android.content.Context;

public class mPlayer {
	private static ArrayList<mSoundTrack> tracks = new ArrayList<mSoundTrack>();

	/**
	 * Добавляет трек из ресурсов
	 *
	 * @param c
	 *            - контекст
	 * @param resid
	 *            - идентификатор ресурса
	 * @param name
	 *            - имя для нового трека
	 * @param looped
	 *            - зацикленность трека
	 */
	public static void addTrack(Context c, int resid, String name,
			boolean looped) {
		mSoundTrack track = new mSoundTrack(c, resid, name, looped);
		tracks.add(track);
	}

	/**
	 * Возвращает трек из списка по его имени
	 *
	 * @param name
	 *            - имя трека
	 * @return возвращает трек с именем name
	 */
	public static mSoundTrack getTrackByName(String name) {
		mSoundTrack t = null;
		for (mSoundTrack a : tracks) {
			if (a.getName() == name) {
				t = a;
				break;
			}
		}
		return t;
	}

	/**
	 * Метод запускает все треки, свойство playable которых имеет значение
	 * истина
	 */
	public static void playAll() {
		for (mSoundTrack a : tracks) {
			if (a.isPlayable()) {
				a.start();
			}
		}
	}

	/**
	 * Метод останавливает все треки
	 *
	 */
	public static void stopAll() {
		for (mSoundTrack a : tracks) {
			a.stop();
		}
	}
}

Тоже на самом деле ничего сложного! В классе имеется статический список треков и метод для добавления трека в список — addTrack(). Помимо этого присутствует метод возвращающий трек по его имени — getTrackByName(String name), если такого имени не оказалось то возвращается null. Ну и собственно то ради чего все это затевалось: метод запуска всех треков (при запуске проверяется имеет ли трек статус проигрываемого) и метод остановки всех треков. Для написания не сложной игры этого простенького менеджера звуков оказалось вполне достаточно!

На сегодня все! жду комментов или примеров работы с SoundPool (Наверняка там все несколько легче).

Читать дальше тут.

Вам понравилось? Было полезно? Поделитесь!

Опубликовать в Facebook
Опубликовать в Google Buzz
Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Мой Мир
Опубликовать в Одноклассники
Опубликовать в Яндекс
Запись опубликована в рубрике Android, Новичку, Программирование с метками , , , , , , . Добавьте в закладки постоянную ссылку.

6 комментариев на «Работа со звуком в Android (Пишем движок часть 7)»

  1. Cfyz говорит:

    «запускает трек если в настройках mSettings есть звук»
    А где определение mSettings?

  2. Иван говорит:

    Здравствуйте. Хотел добавить в Пятнашки музыку. для этого добавил в папку «w» мелодию с именем «track». В классе MainScreen добавил к подключаемым классам mPlayer и в методе onStart() добавил mPlayer.getTrackByName(«track»).setPlayable(true);
    mPlayer.getTrackByName(«track»).forceStart();
    mPlayer.playAll();
    отладчик ошибок никаких не находит, но в эмуляторе игра не работает. Не подскажите в чем причина?

  3. Иван говорит:

    Разобрался что к чему =)

  4. Иван говорит:

    Где можно посмотреть реализацию метода isSound()?

  5. Константин говорит:

    Никогда не делайте так))

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *