Привет Хабр!
Так сложилось, что большую часть жизни я пользовался 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, но пока совершенно нет стимула — в домашней коллекции файлов такого формата нет.
ссылка на оригинал статьи http://habrahabr.ru/post/266127/
Добавить комментарий