Время на прочтение
3 мин
Количество просмотров 32K
Так сложилось, что большую часть жизни я пользовался Windows и привык воспроизводить аудио файлы с помощью Winamp. Он очень удобно интегрируется с командной строкой — запустил любой аудио файл и готово. После перехода на Linux и OS X (в основном по работе, но Mac использую и дома вместе с виндой) возникла острая необходимость найти альтернативу. Перепробывал большое количестко крафических плееров. Основная их проблема — это отсутствие нормальной интеграции с командной строкой и часто поддержка только одной из платформ: либо Linux, либо OS X. С консольными плеерами ситуация получше: mpg123 и mpg321 практически идеально делают именно то, что надо. Вот только появилось одно большое «но». Они не умеют играть .ogg и трекерную музыку (.it, .mod, .xm, .s3m и прочие), которой тоже накопилось достаточно и расставаться с ней совершенно не хотелось.
Дело в том, что за свою программистскую карьеру мне пришлось написать пару мультиплатформных аудио систем для игровых движков: для Linderdaum Engine и для Blippar и ещу одну небольшую для вот этой книжки. Почему бы не применить накопленный опыт, чтобы самому написать проигрыватель? Требования для плеера получились вот такими:
- работать на Windows, Linux и OS X;
- проигрывать MP3, Vorbis, WAV и максимальное разумное кол-во модульных аудио форматов;
- удобная интеграция с командной строкой;
- использовать максимум сторонних библиотех, чтобы не превращать проект в долгострой;
На самом деле первая версия, которая заменила mpg123, была написана за 3 дня. А версия, которая могла проиграть всю музыкальную коллекцию из ~12 тысяч файлов потребовала ровно месяц. В качестве бэк-энда для вывода звука было решено использовать OpenAL (OpenAL Soft на Linux и официальная поддержка на OS X). Для декодинга звуковых форматов используются libogg, libvorbis, minimp3, libmodplug и id3v2lib. Написание плеера «немного» отличается от написания аудиосистемы для игры (кроме того, что необходим только один единственный источник звука без всякого 3D позиционирования и эффектов). По сути главное отличие в том, что звуковые форматы на воле это совсем не то же самое, что звуковые ассеты для игрового проекта. Могут быть битые файлы, странные тэги, нестандартные добавки в конце файла, необычные .mp3 в которых сэмплинг рейт меняется от фрейма к фрейму, могут быть контейнеры .wav у которых внутри сидит .mp3 стрим.
Плеер задумывался как модульный возможностью быстрого расширения для проигрывания других форматов и для использования разных бэк-эндов. В основе всего интерфейс источника звука, абстрактный класс iAudioSource, и интерфейс аудиосистему iAudioSubsystem.
class iAudioSource
{
public:
iAudioSource()
: m_Looping( false )
{}
virtual void BindDataProvider( const std::shared_ptr<iWaveDataProvider>& Provider ) = 0;
virtual void Play() = 0;
virtual void Stop() = 0;
virtual bool IsPlaying() const = 0;
virtual bool IsLooping() const { return m_Looping; }
virtual void SetLooping( bool Looping ) { m_Looping = Looping; }
private:
bool m_Looping;
};
class iAudioSubsystem
{
public:
virtual ~iAudioSubsystem() {};
virtual void Start() = 0;
virtual void Stop() = 0;
virtual std::shared_ptr<iAudioSource> CreateAudioSource() = 0;
virtual void SetListenerGain( float Gain ) = 0;
};
Единственные реализации этих интерфейсов используют OpenAL для вывода звука, поскольку поддержка это API на всех трех платформах вполне достойная.
Чтобы декодировать различные форматы в PCM создаем интерфейс iWaveDataProvider.
class iWaveDataProvider
{
public:
virtual ~iWaveDataProvider() {};
virtual const sWaveDataFormat& GetWaveDataFormat() const = 0;
virtual const uint8_t* GetWaveData() const = 0;
virtual size_t GetWaveDataSize() const = 0;
virtual bool IsStreaming() const { return false; }
virtual bool IsEndOfStream() const { return false; }
virtual void Seek( float Seconds ) {}
virtual size_t StreamWaveData( size_t Size ) { return 0; }
};
И для удобства вот такую фабрику:
std::shared_ptr<iWaveDataProvider> CreateWaveDataProvider( const char* FileName, const std::shared_ptr<clBlob>& Data );
Различные реализации iWaveDataProvider используют сторонние библиотеки для декодирования аудио форматов. Получилось весьма компактно и пригодно для дальнейшего расширения функциональности.
Проект с исходниками доступен здесь: github.com/corporateshark/PortAMP
Возможно однажды добавлю поддержку FLAC, но пока совершенно нет стимула — в домашней коллекции файлов такого формата нет.
Поддержка FLAC теперь тоже есть.
Уже прошли те времена, когда для воспроизведения аудио или видео на сайте нужно было подключать сторонний плеер на Flash — в Adobe решили больше не поддерживать эту технологию, а значит, мы можем вздохнуть с облегчением, потому что HTML5 позволяет создавать плееры с помощью тегов <audio> и <video>.
Чтобы создать плеер, достаточно такого кода для аудио:
<audio controls>
<source src="music.mp3" type="audio/mpeg">
<source src="music.ogg" type="audio/ogg">
</audio>
И такого — для видео:
<video src="video.mp4" poster="poster.jpg" controls></video>
Атрибут controls используется для того, чтобы отобразить элементы управления. Если его не указать, никакого интерфейса не будет: аудиоплеер не будет отображаться, а в видеоплеере просто будет показан кадр из видео или постер.
Обратите внимание, как указан источник. Для видео достаточно прописать атрибут src, а для аудио нужно прописывать дополнительные элементы source, чтобы указать пути и формат файлов. В коде выше добавлено два одинаковых файла, но в разных расширениях — это нужно для того, чтобы прослушать запись можно было на всех устройствах и во всех браузерах, потому что не все из них поддерживают mp3 или какой-то другой формат.
Также внутри плеера можно прописать какой-нибудь текст — его увидят те, у кого не поддерживается HTML5. Правилом хорошего тона считается указание ссылки на скачивание современного браузера.
Вот список атрибутов, которые можно указать для плеера:
- controls — панель управления;
- autoplay — автовоспроизведение;
- loop — цикличность;
- muted — выключение звука;
- poster — обложка видео. Если не указать, будет выбран случайный кадр;
- preload — предварительная загрузка. Существует 3 значения: auto (полностью), metadata (небольшую часть, чтобы определить основные метаданные) и none (без загрузки);
- src — ссылка на файл.
Также можно указать высоту и ширину.
Существует элемент <track>, который размещается внутри плеера, — в нем указывается путь к текстовым файлам: субтитрам или метаданным. Для них прописываются следующие атрибуты:
- default — указывает на дорожку, которая используется по умолчанию;
- kind — тип файла, можно указать следующие значения:
- subtitles — субтитры (стоит по умолчанию),
- captions — субтитры для глухонемых,
- chapters — название глав и их временные рамки,
- descriptions — звуковое описание происходящего для слепых,
- metadata — метаданные;
- label — название дорожки;
- src — путь к файлу;
- srclang — язык дорожки.
Всего этого достаточно, чтобы вставить простой плеер на сайт, но некоторых функций у него все-таки нет:
- можно убрать звук, но нельзя регулировать громкость;
- нельзя менять скорость воспроизведения;
- нельзя поставить на повтор и так далее.
Поэтому мы подключаем JS и пишем свой интерфейс.
Плеер на JS работает, как и любой другой интерфейс: пользователь нажимает на кнопки, скрипт отлавливает эти события и вызывает необходимые функции. Прежде всего нужно создать сам интерфейс:
<div class='video-container'>
<video src="video.mp4" poster='preview.jpg' class='video-player' id='video-player' preload='metadata'></video>
<div class='video-hud'>
<div class='video-hud__element video-hud__action video-hud__action_play' id='video-hud__action'></div>
<div class='video-hud__element video-hud__curr-time' id='video-hud__curr-time'>00:00</div>
<progress value='0' max='100' class='video-hud__element video-hud__progress-bar' id='video-hud__progress-bar'></progress>
<div class='video-hud__element video-hud__duration' id='video-hud__duration'>00:00</div>
<div class='video-hud__element video-hud__mute video-hud__mute_false' id='video-hud__mute'></div>
<input type='range' value='100' max='100' title='Громкость' class='video-hud__element video-hud__volume' id='video-hud__volume'>
<select title='Скорость' class='video-hud__element video-hud__speed' id='video-hud__speed'>
<option value='25'>x0.25</option>
<option value='50'>x0.50</option>
<option value='75'>x0.75</option>
<option value='100' selected>x1.00</option>
<option value='125'>x1.25</option>
<option value='150'>x1.50</option>
<option value='175'>x1.75</option>
<option value='200'>x2.00</option>
</select>
<a class='video-hud__element video-hud__download' title='Скачать' href='video.mp4' download></a>
</div>
</div>
И задать ему стили:
.video-container {
background:#000;
width:80%;
color:#fff;
}
.video-player {
width:100%;
margin:0;
}
.video-hud {
margin:0;
padding:1px;
}
.video-hud__element {
cursor:pointer;
display:inline-block;
vertical-align:middle;
height:30px;
}
.video-hud__action {
width:30px;
}
.video-hud__action_play {
background:#ccc;
border-radius:0 100px 100px 0;
}
.video-hud__action_pause {
background:#c00;
}
.video-hud__mute {
width:30px;
border-radius:100px 100px 100px 100px;
}
.video-hud__mute_true {
background:#c00;
}
.video-hud__mute_false {
background:#ccc;
}
.video-hud__download {
background:#ccc;
width:30px;
border-radius:0 0 100px 100px;
}
Выглядит это вот так:
Нас пока не интересует красивое оформление, но в этом варианте есть всё необходимое:
- кнопка старта и паузы;
- текущее время (в том числе и на прогресс-баре);
- общая длительность;
- кнопка отключения звука;
- шкала громкости;
- выбор скорости;
- кнопка скачивания.
Теперь нужно написать функции, которые будут отдавать команды плееру. Начнем с получения объектов, запуска и паузы:
//Получаем объекты
//Плеер
var videoPlayer = document.getElementById('video-player');
//Время
var progressBar = document.getElementById('video-hud__progress-bar');
var currTime = document.getElementById('video-hud__curr-time');
var durationTime = document.getElementById('video-hud__duration');
//Кнопки
var actionButton = document.getElementById('video-hud__action');
var muteButton = document.getElementById('video-hud__mute');
var volumeScale = document.getElementById('video-hud__volume');
var speedSelect = document.getElementById('video-hud__speed');
function videoAct() { //Запускаем или ставим на паузу
if(videoPlayer.paused) {
videoPlayer.play();
actionButton.setAttribute('class','video-hud__element video-hud__action video-hud__action_play');
} else {
videoPlayer.pause();
actionButton.setAttribute('class','video-hud__element video-hud__action video-hud__action_pause');
}
if(durationTime.innerHTML == '00:00') {
durationTime.innerHTML = videoTime(videoPlayer.duration); //Об этой функции чуть ниже
}
}
Сначала идет проверка, стоит ли видео на паузе — информация об этом содержится в переменной paused объекта videoPlayer (плеер). Затем используются функции play и pause, чтобы запустить и остановить видео соответственно. Для кнопки указываются классы, чтобы было понятно, в каком состоянии находится ролик. Также длительность ролика записывается в специальное поле.
Чтобы функция работала, нужно перехватывать события нажатий на кнопку и на сам ролик:
//Запуск, пауза
actionButton.addEventListener('click',videoAct);
videoPlayer.addEventListener('click',videoAct);
Теперь, когда ролик можно запустить, пора настроить прогресс-бар. Для этого понадобятся 3 функции: перевод секунд в формат «ММ: СС», отображение текущего времени и перемотка.
function videoTime(time) { //Рассчитываем время в секундах и минутах
time = Math.floor(time);
var minutes = Math.floor(time / 60);
var seconds = Math.floor(time - minutes * 60);
var minutesVal = minutes;
var secondsVal = seconds;
if(minutes < 10) {
minutesVal = '0' + minutes;
}
if(seconds < 10) {
secondsVal = '0' + seconds;
}
return minutesVal + ':' + secondsVal;
}
function videoProgress() { //Отображаем время воспроизведения
progress = (Math.floor(videoPlayer.currentTime) / (Math.floor(videoPlayer.duration) / 100));
progressBar.value = progress;
currTime.innerHTML = videoTime(videoPlayer.currentTime);
}
function videoChangeTime(e) { //Перематываем
var mouseX = Math.floor(e.pageX - progressBar.offsetLeft);
var progress = mouseX / (progressBar.offsetWidth / 100);
videoPlayer.currentTime = videoPlayer.duration * (progress / 100);
}
Первая функция получает секунды и возвращает их в формате «ММ: СС». Вторая функция высчитывает текущее время в процентах от общей длительности и двигает полосу прогресса, а также показывает прогресс в виде минут и секунд. При необходимости можно изменить функцию, чтобы она показывала оставшееся время, — для этого нужно отнять текущий момент от длительности и преобразовать с помощью videoTime. А третья функция на основе положения мыши на полосе рассчитывает, куда нужно перемотать видео, и перематывает его.
Перехватываем события:
//Отображение времени
videoPlayer.addEventListener('timeupdate',videoProgress);
//Перемотка
progressBar.addEventListener('click',videoChangeTime);
На очереди — работа со звуком и скоростью:
function videoChangeVolume() { //Меняем громкость
var volume = volumeScale.value / 100;
videoPlayer.volume = volume;
if(videoPlayer.volume == 0) {
muteButton.setAttribute('class','video-hud__element video-hud__mute video-hud__mute_true');
} else {
muteButton.setAttribute('class','video-hud__element video-hud__mute video-hud__mute_false');
}
}
function videoMute() { //Убираем звук
if(videoPlayer.volume == 0) {
videoPlayer.volume = volumeScale.value / 100;
muteButton.setAttribute('class','video-hud__element video-hud__mute video-hud__mute_false');
} else {
videoPlayer.volume = 0;
muteButton.setAttribute('class','video-hud__element video-hud__mute video-hud__mute_true');
}
}
function videoChangeSpeed() { //Меняем скорость
var speed = speedSelect.value / 100;
videoPlayer.playbackRate = speed;
}
Звук хранится в переменной volume, а скорость — в playbackRate. Меняем их значения в зависимости от выбора пользователя.
//Звук
muteButton.addEventListener('click',videoMute);
volumeScale.addEventListener('change',videoChangeVolume);
//Работа со скоростью
speedSelect.addEventListener('change',videoChangeSpeed);
Это необходимый минимум для работы с плеером, но еще можно добавить полноэкранный режим, окно в окне, выбор субтитров и дополнительных дорожек — зная принцип взаимодействия с тегами <audio> и <video>, вы можете разобраться с этим, изучив необходимые события и функции в мануалах.
Кроме воспроизведения видео, плеер можно использовать и для добавления звуковых эффектов в интерфейсы:
- звук щелчка при нажатии на кнопку;
- звук перелистывания во время свайпа;
- звук комкания бумаги при удалении записи из базы данных и так далее.
Для этого нужно создать элемент <audio> без атрибута controls, задать ему id и запускать воспроизведение при каком-нибудь событии.
var buttonA = document.getElementsByid('button');
var clickSound = document.getElementById('click-sound');
function buttonClick() {
clickSound.currTime = 0;
clickSound.play();
}
buttonA.addEventListener('click',buttonClick);
Так можно вызывать звук в любое время — главное, чтобы он был коротким, иначе могут быть проблемы, если пользователь быстро кликает по кнопкам. И еще продолжительные звуки сбивают с толку.
Кроме того, не рекомендуется добавлять такие фичи на сайт, если в этом нет особой необходимости. Потому что в некоторых случаях это может отвлекать пользователей, а в других — сильно замедлять загрузку страницы.
Также можно сделать удобный плеер для гифок:
<video src='file.gif' preload='none' id='gif-player' class='gif-player gif-player_pause' loop></video>
Немного стилей:
.gif-player {
cursor:pointer;
}
.gif-player_pause {
opacity:0.8;
}
И сам скрипт:
var gifPlayer = document.getElementById('gif-player');
function gifAct() {
if(gifPlayer.paused) {
gifPlayer.play();
gifPlayer.setAttribute('class','gif-player gif-player_play');
} else {
gifPlayer.pause();
gifPlayer.currentTime = 0;
gifPlayer.setAttribute('class','gif-player gif-player_pause');
}
}
gifPlayer.addEventListener('click',gifAct);
Такую гифку можно поставить на паузу, поэтому она не загружает страницу. Также пользователь может вообще не запускать и даже не загружать ее.
Встроенный плеер на HTML5 — это лучшее решение, которое доступно современному веб-разработчику. Больше не нужно мучиться с Flash и другими подключаемыми плеерами, потому что есть более удобный вариант, который еще и хорошо оптимизирован и не требует скачивания сторонних приложений.
Russian (Pусский) translation by Yuri Yuriev (you can also view the original English article)
Платформа Android предоставляет ресурсы для управления воспроизведением мультимедиа, которые ваши приложения могут использовать для создания интерфейса между пользователем и его музыкальными файлами. В этой серии уроков мы создадим базовый музыкальный плеер для Android. Приложение представит список песен на устройстве, чтобы пользователь мог выбирать их для воспроизведения. Приложение будет управлять воспроизведением и продолжит исполнение, когда пользователь выйдет из приложения, при этом будет отображаться уведомление.
Введение
Для создания music player потребуется класс ContentResolver
для извлечения треков на устройстве, класс MediaPlayer
для воспроизведения звука и класс MediaController
для управления воспроизведением. Мы также будем использовать Service
для воспроизведения звука, когда пользователь не взаимодействует напрямую с приложением. Дальше можете не смотреть, если вы промежуточный разработчик Android, и, если уже создали несколько приложений, вам будет неинтересно. Вот предварительный вид готового приложения:
В этом уроке мы создадим приложение и запросим пользовательское устройство для аудиофайлов с использованием классов ContentResolver
и Cursor
. В следующей части мы будем использовать образец Adapter
для показа песен в виде списка, начала воспроизведения при выборе элемента из списка. В последнем выпуске серии мы используем класс MediaController
, чтобы дать пользователю контроль над воспроизведением, реализовать функции перемотки вперёд и назад и включить функцию shuffle. По окончании серии мы рассмотрим другие аспекты воспроизведения media, которые могут улучшить приложение, такие как обработка фокуса аудио, представление медиафайлов в разных видах и воспроизведение потокового media .
1. Создание и настройка нового проекта
Шаг 1
Создайте новый проект Android. Если вы используете Eclipse, то пусть IDE (Integrated Development Environment) создаст для вас основной класс Activity
и файл макета. Для некоторых кодов, которые мы используем в этой серии, понадобится минимальный уровень API 16, так что вам нужно будет сделать дополнительные шаги для поддержки более старых версий. Когда проект будет создан, откройте файл Manifest проекта. Внутри элемента manifest
добавьте следующее разрешение:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Мы сделаем это разрешение, чтобы воспроизведение музыки продолжалось, когда устройство не работает. В вашем Manifest должен быть элемент для основного класса Activity
. Добавьте следующие атрибуты в элемент activity
, чтобы установить screenOrientation
и launchMode
:
<activity android:name="com.example.musicplayer.MainActivity" android:label="@string/app_name" android:launchMode="singleTop" android:screenOrientation="portrait" >
Для простоты мы будем придерживаться книжной ориентации. launchMode
поможет процессу перехода к приложению после его удаления. Мы отобразим уведомление о текущей песне, нажатие на уведомление вернёт пользователя в приложение. Мы также будем использовать класс Service
для воспроизведения музыки. Добавьте следующую строку в Manifest проекта внутри элемента application
и после элемента activity
:
<service android:name="com.example.musicplayer.MusicService" />
Измените имя пакета, как хотите и измените имя класса, если хотите.
Шаг 2
Откройте основной файл layout проекта и замените его на следующий layout:
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#FF330000" tools:context=".MainActivity" > <ListView android:id="@+id/song_list" android:layout_width="fill_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
Обязательно измените атрибут tools:context, если ваш основной класс Activity
называется по-другому. Макет включает ListView
, в котором мы представим список песен.
Мы собираемся включить два пункта меню для переключения функции перемешивания и выхода из приложения. Откройте файл главного меню (res/menu/main.xml) и замените его содержимое следующим:
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/action_shuffle" android:icon="@drawable/rand" android:orderInCategory="1" android:showAsAction="always" android:title="Shuffle"/> <item android:id="@+id/action_end" android:icon="@drawable/end" android:orderInCategory="2" android:showAsAction="always" android:title="End"/> </menu>
Если нравится, вы можете хранить строки заголовка в файле res/values/strings.xml. Эти два элемента относятся к drawable файлам. Создайте собственные или используйте эти два изображения для начала:
Мы будем использовать и значок уведомления о воспроизведении. Создайте его или используйте следующий:
Код будет ссылаться на изображения, используя имена rand, end и play, поэтому убедитесь, что вы используете одни и те же имена файлов. Скопируйте изображения в папку (-и) drawables вашего проекта. Мы будем реализовывать эти действия позже.
2. Запрос устройства для песен
Шаг 1
Попробуем запросить устройство пользователя для аудиофайлов. Во-первых, добавьте новый класс Song
. Мы будем использовать этот класс для моделирования данных одного звукового файла. В объявлении класса добавьте три переменные экземпляра данных, которые мы сохраним для каждого трека:
private long id; private String title; private String artist;
Затем добавьте метод конструктора, в котором мы создаём экземпляры переменных:
public Song(long songID, String songTitle, String songArtist) { id=songID; title=songTitle; artist=songArtist; }
Наконец, добавьте методы get для переменных экземпляра:
public long getID(){return id;} public String getTitle(){return title;} public String getArtist(){return artist;}
Если вы планируете использовать больше информации о треке, вы можете добавить дополнительные переменные экземпляра в класс.
Шаг 2
Откройте основной класс Activity
и добавьте imports:
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import android.net.Uri; import android.content.ContentResolver; import android.database.Cursor; import android.widget.ListView;
Объявите следующие переменные экземпляра перед методом onCreate
:
private ArrayList<Song> songList; private ListView songView;
Мы будем хранить песни в списке и отображать их в экземпляре ListView
в главном layout. В onCreate
после установки вида содержимого извлеките экземпляр ListView
, используя ID, который мы дали ему в главном макете:
songView = (ListView)findViewById(R.id.song_list);
Создайте список, как показано ниже:
songList = new ArrayList<Song>();
Затем в объявлении основного класса Activity
после существующих методов создайте вспомогательный метод для извлечения информации о звуковом файле:
public void getSongList() { //retrieve song info }
Внутри этого метода создайте экземпляр ContentResolver
, извлеките URI для внешних музыкальных файлов и создайте экземпляр Cursor
, используя экземпляр ContentResolver
для запроса музыкальных файлов:
ContentResolver musicResolver = getContentResolver(); Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
Теперь мы можем перебрать результаты, сначала проверив, что у нас достоверные данные:
if(musicCursor!=null && musicCursor.moveToFirst()){ //get columns int titleColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media.TITLE); int idColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media._ID); int artistColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media.ARTIST); //add songs to list do { long thisId = musicCursor.getLong(idColumn); String thisTitle = musicCursor.getString(titleColumn); String thisArtist = musicCursor.getString(artistColumn); songList.add(new Song(thisId, thisTitle, thisArtist)); } while (musicCursor.moveToNext()); }
Сначала мы извлекаем индексы столбцов для интересующих нас элементов данных для каждой песни, затем мы используем их для создания нового объекта Song
и добавления его в список, перед тем как продолжить обзор результатов.
Вернитесь в onCreate
после кода, который мы добавили, вызовите этот новый метод:
getSongList();
3. Отображение композиций
Шаг 1
Теперь мы можем отобразить список песен в пользовательском интерфейсе. В методе onCreate
после вызова вспомогательного метода, который мы создали минуту назад, давайте отсортируем данные так, чтобы песни представлялись в алфавитном порядке:
Collections.sort(songList, new Comparator<Song>(){ public int compare(Song a, Song b){ return a.getTitle().compareTo(b.getTitle()); } });
Мы используем переменную title
в классе Song
, используя добавленные методы get, чтобы реализовать метод compare
, сортируя песни по заголовкам.
Шаг 2
Определим layout для представления каждой песни в списке. Добавьте новый файл в папку res/layout вашего проекта, назвав его song.xml и введя следующее:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="songPicked" android:orientation="vertical" android:padding="5dp" > <TextView android:id="@+id/song_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF99" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/song_artist" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF99" android:textSize="18sp" /> </LinearLayout>
Не стесняйтесь изменять layout по своему вкусу. Каждая песня в списке будет представлена строками названия и артиста, поэтому мы будем использовать TextViews
для отображения этих данных. Обратите внимание: в теге открытия LinearLayout
указан атрибут onClick
. Мы будем использовать этот метод в основном классе Activity
, чтобы реагировать на выбор песни в списке, проигрывая песню, представленную элементом списка, который был выбран.
Шаг 3
Мы будем использовать Adapter для отображения песен в виде списка. Добавьте в приложение новый класс SongAdapter или назовите иначе. При создании класса назначьте ему суперкласс android.widget.BaseAdapter
. Eclipse должен вставить следующую схему:
public class SongAdapter extends BaseAdapter { @Override public int getCount() { // TODO Auto-generated method stub return 0; } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return 0; } @Override public View getView(int arg0, View arg1, ViewGroup arg2) { // TODO Auto-generated method stub return null; } }
Вам нужно будет добавить следующие imports:
import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.widget.LinearLayout; import android.widget.TextView;
В объявлении класса задайте следующие переменные:
private ArrayList<Song> songs; private LayoutInflater songInf;
Мы передадим список композиций из основного класса Activity
и используем LayoutInflater
для сопоставления строк заголовка и исполнителя с TextViews
в созданном нами layout песни.
После переменных экземпляра придайте адаптеру метод конструктора для их создания:
public SongAdapter(Context c, ArrayList<Song> theSongs){ songs=theSongs; songInf=LayoutInflater.from(c); }
Измените содержимое метода getCount
, чтобы вернуть размер списка:
@Override public int getCount() { return songs.size(); }
Вы можете оставить методы getItem
и getItemId
нетронутыми. Обновите реализацию метода getView
, как показано ниже:
@Override public View getView(int position, View convertView, ViewGroup parent) { //map to song layout LinearLayout songLay = (LinearLayout)songInf.inflate (R.layout.song, parent, false); //get title and artist views TextView songView = (TextView)songLay.findViewById(R.id.song_title); TextView artistView = (TextView)songLay.findViewById(R.id.song_artist); //get song using position Song currSong = songs.get(position); //get title and artist strings songView.setText(currSong.getTitle()); artistView.setText(currSong.getArtist()); //set position as tag songLay.setTag(position); return songLay; }
Мы устанавливаем текст названия и исполнителя, выбирая правильный экземпляр Song
из списка, используя индекс позиции, сопоставляя эти строки с представлениями, добавленными в файл макета песни. Мы также устанавливаем позицию в качестве тега вида, которая позволит нам играть правильную песню, когда пользователь нажимает на элемент в списке. Помните, что файл формата song.xml включал атрибут onClick
. Мы будем использовать метод, указанный там, чтобы получить тег в Activity
.
Шаг 3
Вернувшись в основной класс Activity
, в методе onCreate
после сортировки списка создайте новый экземпляр класса Adapter
и установите его в ListView
:
SongAdapter songAdt = new SongAdapter(this, songList); songView.setAdapter(songAdt);
Когда вы запускаете приложение, оно должно отображать список песен на устройстве, щёлкнув по ним, приложение будет вызывать исключение на данный момент, но мы реализуем обработчик щелчка в следующем уроке.
Заключение
Теперь мы настроили приложение для чтения песен с пользовательского устройства. В следующей части мы начнем воспроизведение, когда пользователь выберет песню, используя класс MediaPlayer
. Мы реализуем воспроизведение с использованием класса Service
, чтобы оно продолжалось, пока пользователь занят другими приложениями. Наконец, мы будем использовать класс MediaController
, чтобы дать пользователю управлять воспроизведением.
В это статье вы прочитает о том, как сделать аудиоплеер на JavaScript и HTML, если вы задаётесь вопросом как это сделать, то вам сюда.
Также посмотрите наш учебник по HTML, если вы его плохо знаете.
Создание аудиоплеера:
Для начала разберём логику плеера и что мы тут реализуем, а реализуем переключение треков, и сам плейлист, что касается паузы, то в HTML уже по стандарту это есть.
HTML:
Начнём с HTML, тут вообще не чего сложного нет, надо просто написать тег <audio>
внутри документа и добавить атрибут controls
.
<audio id=«audio» src=«./audio/treck1.mp3» controls></audio> |
Вот результат.
Как видите стандартный HTML плеер выглядит красиво, но есть одна проблема, его возможности ограниченны, вы можете только останавливать трек и менять громкость и всё, что на мой взгляд не достаточно, поэтому мы уберём атрибут controls
, после чего у нас будет пустой экран.
Так как теперь у нас пустой экран, мы добавим кнопки для управления, также тег для аудио дорожек.
<div id=«controls»> <div class=«audio-track»><div class=«time»></div></div> <button class=«play»>Play</button> <button class=«pause»>Pause</button> <button class=«prev»><prev</button> <button class=«next»>next></button> </div> |
Давайте разберём, <div>
с классом audio-track
, это аудио дорожка, внутри него имеется <div>
с классом time
, это остаток сколько осталось до окончания.
Также дальше идут четыре тега <button>
, это кнопки, первая для проигрывания музыки, вторая для паузы, третья переключает на предыдущий трек, четвёртая кнопка на следующий.
CSS:
Теперь перейдём к CSS, с помощью его мы изменим только дорожку, кнопки оставим по умолчанию, как они сделаны в браузере.
.audio-track { width: 150px; height: 3px; background-color: #dddddd; margin: 20px 0 } .time { width: 0; height: 3px; background-color: #474747 } |
Вот что получилось.
У нас появилась не большая дорожка, серого цвета, также при проигрывание она будет закрашиваться в почти чёрный цвет, за счёт увеличения <div>
с классом time.
JavaScript:
Пришло время самому главному, к созданию основной логике на чистом JavaScript, для начала мы возьмём все элементы из HTML.
let audio = document.getElementById(«audio»); // Берём элемент audio let time = document.querySelector(«.time»); // Берём аудио дорожку let btnPlay = document.querySelector(«.play»); // Берём кнопку проигрывания let btnPause = document.querySelector(«.pause»); // Берём кнопку паузы let btnPrev = document.querySelector(«.prev»); // Берём кнопку переключения предыдущего трека let btnNext = document.querySelector(«.next»); // Берём кнопку переключение следующего трека |
Мы тут просто взяли элементы с которыми будим работать, элемент <audio>
берём через id, а остальные через селектор.
Дальше сделаем массив с названиями треков и переменную в которой будет хранится индекс трека в массиве.
// Массив с названиями песен let playlist = [ ‘treck1.mp3’, ‘treck2.mp3’, ‘treck3.mp3’, ‘treck4.mp3’, ]; let treck; // Переменная с индексом трека // Событие перед загрузкой страницы window.onload = function() { treck = 0; // Присваиваем переменной ноль } |
Самое интересное в этом коде, это window.onload
, оно нужно что бы выполнять какие то действия, во время загрузки страницы, в нашем случае, присваивает переменной treck значение ноль.
Тут у многих возник вопрос, почему надо присваивать значение переменной именно во время загрузки страница, а не во время объявления переменной, так сделано потому что иначе, её значение всегда было бы ноль, нам же надо использовать для переключения песен.
Теперь перейдём к функции для переключения песен.
function switchTreck (numTreck) { // Меняем значение атрибута src audio.src = ‘./audio/’ + playlist[numTreck]; // Назначаем время песни ноль audio.currentTime = 0; // Включаем песню audio.play(); } |
В начале мы в функции передаём индекс песни, которая нам нужна, следующие меняем путь до трека, с помощью audio.src
назначаем путь до песни которая нам нужна, взяв название песни из playlist
.
Потом назначаем audio.currentTime
значение ноль, оно отвечает на какой минуте проигрывается песня, то есть мы песню ставим на нулевую секунду.
Последнее это запуск песни через audio.play()
.
Теперь перейдём к обработку событий этих кнопок, для работы с плеером и музыкой.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
btnPlay.addEventListener(«click», function() { audio.play(); // Запуск песни // Запуск интервала audioPlay = setInterval(function() { // Получаем значение на какой секунде песня let audioTime = Math.round(audio.currentTime); // Получаем всё время песни let audioLength = Math.round(audio.duration) // Назначаем ширину элементу time time.style.width = (audioTime * 100) / audioLength + ‘%’; // Сравниваем, на какой секунде сейчас трек и всего сколько времени длится // И проверяем что переменная treck меньше четырёх if (audioTime == audioLength && treck < 3) { treck++; // То Увеличиваем переменную switchTreck(treck); // Меняем трек // Иначе проверяем тоже самое, но переменная treck больше или равна четырём } else if (audioTime == audioLength && treck >= 3) { treck = 0; // То присваиваем treck ноль switchTreck(treck); Меняем трек } }, 10) }); |
Это пожалуй самая сложная часть программы, когда мы нажимаем кнопку «Play».
Первым делом начинаем проигрывать песню, потом запускаем интервал, он нам нужен, что бы отследить, когда переключать трек на следующий.
Внутри интервала присваиваем переменной audioTime
на какой секунде сейчас трек, и переменной audioLength
, присваиваем сколько всего секунд длится песня, потом вычисляем по формуле сколько процентов песни уже проигралась и назначаем это значение ширине элемента time
, тем самым мы создали линию прогресса.
Идёт условие, где проверяем что переменная audioTime
и audioLength
, это нужно что бы убедиться в том что песня закончилась, также проверяем переменную treck
, что бы она была меньше трёх, это нужно что бы её значение не стало больше индекса массива и песни не остановились.
Если условие верно, то увеличиваем переменную treck
и меняем песню используя функцию switchTreck
.
Иначе опять идёт проверка на то, что песня закончилась, но уже смотрим что бы переменная treck
, была больше или равна трём, если верна присваиваем ей ноль и также меняем трек.
Дальше идёт обработки кнопки пауза.
btnPause.addEventListener(«click», function() { audio.pause(); // Останавливает песню clearInterval(audioPlay) // Останавливает интервал }); |
Тут даже не чего рассказывать, всё понятно из комментариев к коду.
Последнее что надо разобрать, это кнопки переключений песен, вот как переключаем на предыдущую.
btnPrev.addEventListener(«click», function() { // Проверяем что переменная treck больше нуля if (treck > 0) { treck—; // Если верно, то уменьшаем переменную на один switchTreck(treck); // Меняем песню. } else { // Иначе treck = 3; // Присваиваем три switchTreck(treck); // Меняем песню } }); |
Думаю из комментариев всё понятно, не буду объяснять что к чему. Вот как переключать на следующую песню.
btnNext.addEventListener(«click», function() { // Проверяем что переменная treck больше трёх if (treck < 3) { // Если да, то treck++; // Увеличиваем её на один switchTreck(treck); // Меняем песню } else { // Иначе treck = 0; // Присваиваем ей ноль switchTreck(treck); // Меняем песню } }); |
На этом всё заканчивается, всё прекрасно работает и вот результат.
Вывод:
В этой статье вы посмотрели как сделать аудиоплеер на JavaScript и HTML, думаю вам понравилось.
Также надо сказать, что тут ещё многое можно доработать и сделать, к примеру, вывод всех треков или изменение громкости и т.д..
Но тогда бы статья получилось очень большой, на мой взгляд она и так не маленькая, поэтому не стал этого делать.
Но если вы хотите доработать аудиоплеер на JavaScript, то скачайте файлы его и зайдите по этой ссылки, там всё что нужно знать для работы с аудио в JS.
Подписываетесь на соц-сети:
Оценка:
Загрузка…
Также рекомендую:
- 1. Структура проекта
- 2. widget.ui
- 3. SimplePlayer.pro
- 4. widget.h
- 5. widget.cpp
- 6. Итог
- 7. Видеоурок
Предлагаю написать простенький аудио плеер для mp3 файлов с использованием Qt/C++, который будет иметь плейлист, возможность запуска/паузы/остановки треков, а также пролистывания треков.
Для реализации данной задумки в Qt имеются классы
QMediaPlayer
и
QMediaPlaylist,
которые относятся к модулю
multimedia.
А для отображения плейлиста воспользуемся
QStandardItemModel
и
QTableView.
Статьи данного цикла:
- Кастомизация плеера в стиле AIMP
Структура проекта
SimplePlayer.pro
— профайл проекта;
main.cpp
— файл с функцией main;
widget.ui
— файл формы окна приложения;
widget.h
— заголовочный файл окна приложения;
widget.cpp
— файл исходных кодов окна приложения;
buttons.qrc
— ресурсный файл иконок кнопок приложения.
widget.ui
Интерфейс приложения сделаем с использованием графического дизайнера, и выглядеть он должен будет следующим образом.
В состав интерфейса приложения входят следующие элементы:
btn_add (QToolButton*)
— отвечает за добавление треков в плейлист;
btn_next
(QToolButton*)
— отвечает за пролистывание плейлиста вперёд;
btn_previous (QToolButton*)
— отвечает за пролистывание плейлиста назад;
btn_play (QToolButton*)
— отвечает за воспроизведение трека;
btn_pause
(QToolButton*)
— отвечает за постановку трека на паузу;
btn_stop (QToolButton*)
— отвечает за остановку трека;
currentTrack (QLabel*)
— лейбл, в котором будет отображаться текущий трек;
playlistView (QTableView*)
— таблица, отвечающая за отображение плейлиста.
SimplePlayer.pro
В профайле проекта не забудьте подключить модуль
multimedia,
иначе классы
QMediaPlayer
и
QMediaPlaylist
будут недоступны.
#------------------------------------------------- # # Project created by QtCreator 2016-06-29T11:25:56 # #------------------------------------------------- QT += core gui multimedia greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = SimplePlayer TEMPLATE = app SOURCES += main.cpp widget.cpp HEADERS += widget.h FORMS += widget.ui RESOURCES += buttons.qrcwidget.h
Для реализации отображения плейлиста, придется использовать QStandardItemModel. В неё будут помещаться пути к аудио файлам, а также имена аудио файлов. В первой колонке будет имя аудио файла, а во второй будет полный путь, но данная колонка будет скрыта в объекте QTableView, который будет отвечать за отображение плейлиста.
Также пути к файлом в качестве медиа источников необходимо будет поместить в объект QMediaPlaylist, который будет помещён в QMediaPlayer.
Указатели на эти объекты помещаются в заголовочном файле окна приложения. Также здесь присутствует автогенерированый через дизайнер интерфейсов слот для обработки нажатия по кнопке добавления треков в плейлист.
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QStandardItemModel> #include <QMediaPlayer> #include <QMediaPlaylist> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private slots: void on_btn_add_clicked(); // Слот для обработки добавления треков через диалоговое окно private: Ui::Widget *ui; QStandardItemModel *m_playListModel; // Модель данных плейлиста для отображения QMediaPlayer *m_player; // Проигрыватель треков QMediaPlaylist *m_playlist; // Плейлиста проигрывателя }; #endif // WIDGET_Hwidget.cpp
Для реализации плеера необходимо инициализировать объекты
QMediaPlayer, QMediaPlaylist
и
QStandardItemModel,
которые были объявлены в заголовочном файле окна приложения. В первой половине конструктора производится настройка внешнего вида таблицы для отображения плейлиста, тогда как во второй настройка самого плеера. Управление плеером осуществляется через кнопки, которые подключены к управляющим слотам
m_playlist
(для навигации) и
m_player
(для запуска/паузы/остановки).При изменении текущего трека, плеер автоматически завершает воспроизведение того, трека который был до изменения, и запускает на воспроизведение новый трек.
В силу того, что
QMediaPlaylist
не имеет модели для отображения в таблице, мы воспользуемся классом
QStandardItemModel,
поэтому придётся добавлять данные о путях к файлам и туда, и туда.#include "widget.h" #include "ui_widget.h" #include <QFileDialog> #include <QDir> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // Настройка таблицы плейлиста m_playListModel = new QStandardItemModel(this); ui->playlistView->setModel(m_playListModel); // Устанавливаем модель данных в TableView // Устанавливаем заголовки таблицы m_playListModel->setHorizontalHeaderLabels(QStringList() << tr("Audio Track") << tr("File Path")); ui->playlistView->hideColumn(1); // Скрываем колонку, в которой хранится путь к файлу ui->playlistView->verticalHeader()->setVisible(false); // Скрываем нумерацию строк ui->playlistView->setSelectionBehavior(QAbstractItemView::SelectRows); // Включаем выделение строк ui->playlistView->setSelectionMode(QAbstractItemView::SingleSelection); // Разрешаем выделять только одну строку ui->playlistView->setEditTriggers(QAbstractItemView::NoEditTriggers); // Отключаем редактирование // Включаем подгонку размера последней видимой колонки к ширине TableView ui->playlistView->horizontalHeader()->setStretchLastSection(true); m_player = new QMediaPlayer(this); // Инициализируем плеер m_playlist = new QMediaPlaylist(m_player); // Инициализируем плейлист m_player->setPlaylist(m_playlist); // Устанавливаем плейлист в плеер m_player->setVolume(70); // Устанавливаем громкость воспроизведения треков m_playlist->setPlaybackMode(QMediaPlaylist::Loop); // Устанавливаем циклический режим проигрывания плейлиста // подключаем кнопки управления к слотам управления // Здесь отметим, что навигация по плейлисту осуществляется именно через плейлист // а запуск/пауза/остановка через сам плеер connect(ui->btn_previous, &QToolButton::clicked, m_playlist, &QMediaPlaylist::previous); connect(ui->btn_next, &QToolButton::clicked, m_playlist, &QMediaPlaylist::next); connect(ui->btn_play, &QToolButton::clicked, m_player, &QMediaPlayer::play); connect(ui->btn_pause, &QToolButton::clicked, m_player, &QMediaPlayer::pause); connect(ui->btn_stop, &QToolButton::clicked, m_player, &QMediaPlayer::stop); // При даблклике по треку в таблице устанавливаем трек в плейлисте connect(ui->playlistView, &QTableView::doubleClicked, [this](const QModelIndex &index){ m_playlist->setCurrentIndex(index.row()); }); // при изменении индекса текущего трека в плейлисте, устанавливаем название файла в специальном лейбле connect(m_playlist, &QMediaPlaylist::currentIndexChanged, [this](int index){ ui->currentTrack->setText(m_playListModel->data(m_playListModel->index(index, 0)).toString()); }); } Widget::~Widget() { delete ui; delete m_playListModel; delete m_playlist; delete m_player; } void Widget::on_btn_add_clicked() { // С помощью диалога выбора файлов делаем множественный выбор mp3 файлов QStringList files = QFileDialog::getOpenFileNames(this, tr("Open files"), QString(), tr("Audio Files (*.mp3)")); // Далее устанавливаем данные по именам и пути к файлам // в плейлист и таблицу отображающую плейлист foreach (QString filePath, files) { QList<QStandardItem *> items; items.append(new QStandardItem(QDir(filePath).dirName())); items.append(new QStandardItem(filePath)); m_playListModel->appendRow(items); m_playlist->addMedia(QUrl(filePath)); } }Итог
После того, как приложение запустится, Вы сможете открыть mp3 треки и прослушать их.
Скачать Qt Audio Player
Видеоурок
Данная статья является переводом. Ссылка на оригинал.
В этой статье мы напишем музыкальный плеер, который будет выглядеть так:
Это и все последующие изображения взяты отсюда.
Подготовка и настройка среды
Я предполагаю, что у вас есть знания о следующих технологиях:
- JavaScript
- HTML/CSS
Настройка среды проста: у вас должен быть предварительно установлен node.js для запуска команды в терминале.
Перейдите в каталог, в котором вы хотите создать проект. Теперь запустите терминал и введите приведенную ниже команду, чтобы установить react-проект.
npx create-react-app react-music-player
Удалите шаблон полностью и ненужный код. Теперь мы можем продолжить.
Зависимости
Нам нужно установить следующие библиотеки в наш проект:
- use-sound будет обрабатывать аудиофайл. Он будет загружать, воспроизводить и приостанавливать звук вместе с другими функциями.
Установите его с помощью следующей команды:
npm i use-sound
- react-icons добавит значки воспроизведения, паузы, следующей и предыдущей композиции в плеер.
Установите его с помощью следующей команды:
npm i react-icons
Player.js
Создайте каталог component
в папке src
. Внутри создайте компонент с именем Player.js
. Этот компонент будет нашим музыкальным проигрывателем.
Импорт
Библиотеки, которые нужно импортировать в файл:
import { useEffect, useState } from "react";
import useSound from "use-sound"; //для работы со звуком
import qala from "../assets/qala.mp3"; // импорт музыки
import { AiFillPlayCircle, AiFillPauseCircle } from "react-icons/ai"; // иконки для воспроизведения и паузы
import { BiSkipNext, BiSkipPrevious } from "react-icons/bi"; // иконки для следующего и предыдущего трека
import { IconContext } from "react-icons"; // для кастомизации иконок
Воспроизведение и приостановка звука
Давайте реализуем обязательную функцию проигрывателя, которая отвечает за воспроизведение и приостановку звука.
Вверху у нас есть состояние isPlaying
для хранения текущего статуса проигрывателя. Это будет полезно при условном рендеринге значка воспроизведения/паузы в соответствии со статусом проигрывателя.
const [isPlaying, setIsPlaying] = useState(false);
Нам нужно инициализировать файл useSound
со звуком. Он вернет воспроизведение, паузу, продолжительность и метод звука.
const [play, { pause, duration, sound }] = useSound(qala);
play
и pause
для воспроизведения и приостановки звука. duration
для длины дорожки в миллисекундах. sound
предоставит нам метод howler.js для звука.
Создайте функцию для обработки кнопок воспроизведения и паузы. Вот код для него.
const playingButton = () => {
if (isPlaying) {
pause(); // приостанавливаем воспроизведение звука
setIsPlaying(false);
} else {
play(); // воспроизводим аудиозапись
setIsPlaying(true);
}
};
Теперь пришло время добавить компонент пользовательского интерфейса плеера в return
. Вот код для него.
return (
<div className="component">
<h2>Playing Now</h2>
<img
className="musicCover"
src="https://picsum.photos/200/200"
/>
<div>
<h3 className="title">Rubaiyyan</h3>
<p className="subTitle">Qala</p>
</div>
<div>
<button className="playButton">
<IconContext.Provider value={{ size: "3em", color: "#27AE60" }}>
<BiSkipPrevious />
</IconContext.Provider>
</button>
{!isPlaying ? (
<button className="playButton" onClick={playingButton}>
<IconContext.Provider value={{ size: "3em", color: "#27AE60" }}>
<AiFillPlayCircle />
</IconContext.Provider>
</button>
) : (
<button className="playButton" onClick={playingButton}>
<IconContext.Provider value={{ size: "3em", color: "#27AE60" }}>
<AiFillPauseCircle />
</IconContext.Provider>
</button>
)}
<button className="playButton">
<IconContext.Provider value={{ size: "3em", color: "#27AE60" }}>
<BiSkipNext />
</IconContext.Provider>
</button>
</div>
</div>
);
Для обложки я использовал Loren Picsum для генерации случайного изображения.
Вы можете посмотреть здесь CSS-файл:
body {
background-color: #e5e5e5;
}
.App {
font-family: sans-serif;
text-align: center;
}
.component {
background-color: white;
width: 25%;
max-width: 600px;
margin: 1em auto;
padding-bottom: 2em;
border: 0.1px solid black;
border-radius: 10px;
}
.musicCover {
border-radius: 10%;
}
.playButton {
background: none;
border: none;
align-items: center;
justify-content: center;
}
.subTitle {
margin-top: -1em;
color: #4f4f4f;
}
.time {
margin: 0 auto;
width: 80%;
display: flex;
justify-content: space-between;
color: #828282;
font-size: smaller;
}
.timeline {
width: 80%;
background-color: #27ae60;
}
input[type="range"] {
background-color: #27ae60;
}
@media (max-width: 900px) {
.component {
width: 50%;
}
}
Запустите сервер react. Если все хорошо, вы сможете увидеть экран ниже.
Нажмите на кнопку воспроизведения, чтобы воспроизвести аудио.
Добавление временной шкалы аудио с текущим временем и продолжительностью аудио
Теперь давайте добавим временную шкалу в плеер. Временная шкала будет контролироваться пользователем. Любые изменения в нем изменят текущую позицию аудио.
Давайте посмотрим на состояние, которое мы используем. Ниже приведены комментарии для объяснения каждого состояния.
const [currTime, setCurrTime] = useState({
min: "",
sec: "",
}); // текущее положение звука в минутах и секундах
const [seconds, setSeconds] = useState(); // текущая позиция звука в секундах
Мы получаем свойства длительности из файла useSound
. Поскольку продолжительность указывается в миллисекундах, мы преобразовали ее в минуты и секунды.
useEffect(() => {
const sec = duration / 1000;
const min = Math.floor(sec / 60);
const secRemain = Math.floor(sec % 60);
const time = {
min: min,
sec: secRemain
};
Теперь для текущей позиции аудио у нас есть метод sound.seek([])
. Мы запускаем эту функцию каждую секунду, чтобы изменить текущую позицию проигрывания звука. Затем получаем значение позиции проигрывания в секундах. Переводим в минуты и секунды. После преобразования мы устанавливаем состояние с текущим значением. Вот код для него.
useEffect(() => {
const interval = setInterval(() => {
if (sound) {
setSeconds(sound.seek([])); // устанавливаем состояние с текущим значением в секундах
const min = Math.floor(sound.seek([]) / 60);
const sec = Math.floor(sound.seek([]) % 60);
setCurrTime({
min,
sec,
});
}
}, 1000);
return () => clearInterval(interval);
}, [sound]);
Теперь о возвращаемом значении. Вот код.
<div>
<div className="time">
<p>
{currTime.min}:{currTime.sec}
</p>
<p>
{time.min}:{time.sec}
</p>
</div>
<input
type="range"
min="0"
max={duration / 1000}
default="0"
value={seconds}
className="timeline"
onChange={(e) => {
sound.seek([e.target.value]);
}}
/>
</div>
Значение входного сигнала диапазона является second
—состоянием, которое сообщает позицию проигрывания аудио. При изменении диапазона пользователем, мы вызываем метод soud.seek()
, чтобы изменить текущую позицию аудио.
Вывод
После успешного завершения проекта вы сможете увидеть:
Ссылка на код
Вы можете посмотреть полный проект с кодом и выводом по ссылке.
Дополнительные возможности
Вы можете работать над музыкальным проигрывателем, чтобы добавить дополнительные функции, например:
- Приложение загружает много песен, однако в настоящее время воспроизводит только одну песню. Используйте кнопки перемотки трека для смены трека.
- Изменение названия и альбома аудио в соответствии с проигрываемой песней.
- Добавьте больше функций, которые, по вашему мнению, должен иметь музыкальный проигрыватель.
Заключение
Мы создали собственный музыкальный плеер. Этот проект поможет вам в обработке аудиофайлов в React. Мы добавили функции воспроизведения и паузы. Также добавлена временная шкала аудио. Пользователи могут изменить текущую позицию аудио на временной шкале. Не стесняйтесь добавлять дополнительные функции в проект. Я надеюсь, что этот проект помог вам понять метод обработки музыки в React.
***
Для создания проигрывателя, будем использовать элемент управления Media Player, который поддерживает следующие форматы:
— Advanced Streaming Format (ASF)
— Video On Demand (VOD)
— Moving Picture Experts Group 1,2,3 (MPEG 1,2,3)
— Real Audio (RA)
— Real Video (RV)
— Audio – Video Interleaved (AVI)
— Quick Time (MOV)
— Musical Instrument Digital Interface (MIDI)
— Indeo 5
— Waveform Audio (WAV)
— Sound File (SND)
— UNIX audio (AU)
— Audio Interchange File Format (AIFF)
Элемент управления Media Player представляет собой ActiveX, основывающийся на компоненте DirectShow уровня DirectX Media. Первое, что необходимо сделать, создать приложение на основе диалога с помощью мастера AppWizard.Следующий шаг, добавление к проекту элемента, делается это через «Project – Add To Project – Components and Controls»
Далее в появившемся окне открываем папку «Registered ActiveX Controls», находим ссылку «Windows Media Player.lnk» и жмем Insert
Нас спросят, хотим ли мы подключить компонент? Соглашайтесь. 🙂
После, откроется окно, где Вы можете поменять имена у подключаемых файлов. Когда компонент добавлен, в нашем проекте появится два новых файла. В них находится класс CMediaPlayer, который выполняет роль оболочки для элемента Media Player, а в редакторе ресурсов появится элемент Windows Media Player. Поместите его на свой диалог, в свойствах уберите галочку с пункта «Visible».
Теперь необходимо создать указатель с типом CMediaPlayer, в файле заголовке «ИмяВашегоПроектаDlg.h» напишите следующее:
перед этим не забудьте добавить файл «mediaplayer.h»
Далее в инициализации диалога OnInitDialog() мы должны получить указатель на элемент Media Player, следующим способом:
m_pMediaPlayer = (CMediaPlayer *)GetDlgItem(IDC_MP);
Поместите на диалог кнопки с заголовками «Load…,Play,Pause,Stop» и Edit Box. В обработчике сообщения к кнопке «Load…» напишите:
CFileDialog m_dlg(TRUE,NULL,NULL,NULL,"MPEG Audio Files(*.mp3)|*.mp3|"); if (m_dlg.DoModal() == IDOK) { m_pMediaPlayer->SetFileName(m_dlg.GetPathName()); m_edit.SetWindowText(m_dlg.GetPathName()); }
Функция SetFileName() устанавливает файл который нужно воспроизвести. В Edit Box помещаем путь к файлу.
Обработчик сообщения кнопки «Play»: m_pMediaPlayer->Play();
Обработчик сообщения кнопки «Pause»: m_pMediaPlayer->Pause();
Обработчик сообщения кнопки «Stop»: m_pMediaPlayer->Stop();
m_pMediaPlayer->SetCurrentPosition(0); Данная функция устанавливает текущую точку воспроизведения.
Вот некоторые из наиболее часто используемых функций:
GetVolume() – получить значение громкости
SetVolume() – установить значение громкости
GetCurrentPosition() – получить текущую позицию воспроизведения
GetDuration() – возвращает длительность воспроизведения в секундах
Все теперь жмите F7 и Ваш собственный проигрыватель готов.