Для начала расскажу немного о том, что это:
Audiere — это высокоуровневый аудио-API с открытым исходным кодом под лицензией LGPL. Его можно использовать во множестве языков, включая Java, C++, Python, Delphi и др. Разрешается использовать в коммерческих приложениях свободным образом, если исходный код не будет затронут (подробности в документации к библиотеке).
Подготовимся к реализации простейшего примера на C++:
- Скачиваем библиотеку на оф.сайте (в моём случае — это Win32 Binary Release)
- Традиционно переносим файл «audiere.lib» в папку «lib» компилятора, а заголовочник «audiere.h» также в папку «include» вашего компилятора ***пути к папке компилятора для CodeBlocks «Program Files(x86)/CodeBlocks/MinGW/», для Microsoft Visual Studio - «Program Files(x86)/Microsoft Visual Studio/VC/»
- Создаём для примера консольный проект C++
- В настройках линкера в проекте добавляем «audiere.lib»
- Не забываем «audiere.dll» из папки «bin» положить рядом с исходниками нашего проекта, а затем и рядом с exe-файлом нашей программы.
- Необходимо подключить заголовочные файлы:
#include <iostream> //нужен для вывода строк "cout<<"
#include "conio.h" //нужен намеренно для "getche()", а не "cin>>"
#include "windows.h" //библиотека audiere её требует
#include "audiere.h" //сама библиотека
using namespace std;
using namespace audiere; //подключаем пространства имён для более короткой записи
- Далее главная функция:
int main()
{
setlocale(0, "Russian"); //пусть наша консоль говорит по-русски
cout<<"Простейшее воспроизведение звука"<<endl;
AudioDevicePtr device = OpenDevice(); //Для начала нужно открыть AudioDevice
OutputStreamPtr sound = OpenSound(device , "sound.wav" , false); //создаем поток для нашего звука
sound->play(); //проигрываем наш звук
getche(); //ждём нажатия любой клавиши прежде чем выйти из программы
}
Теперь, комментарии чуть более развернутые:
AudioDevicePtr device = OpenDevice();
Здесь мы создаем, по концепции библиотеки указатель device (не совсем явный, но всё же указатель). OpenDevice() можно оставить без аргументов, тогда библиотека сама выберет подходящее устройство.
Далее, открываем наш файл в поток:
OutputStreamPtr sound = OpenSound(device , "sound.wav" , false);
Открывая наш звук, в OpenSound нужно передать три аргумента:
1. device — устройство куда будет происходить вывод
2. «sound.wav» — наш произвольный звук
3. false или true — хотим мы, чтобы наш звук был загружен в память и воспроизведён(false) или, посредством потока (например, если это большой файл), воспроизводился не загружаясь полностью в память(true). Для саундтреков обязательно «true», иначе всю память займёт звук.
sound->play();
Проигрываем наш звук! Как видно, всё очень просто. Для звуков можно установить громкость:
sound->setVolume(1.0f); //полная громкость (для половинной "0.5f" соответственно)
Можно сделать звук повторяющимся (зацикленным):
sound->setRepeat(true);
Остановить воспроизведение данного потока:
sound->stop();
Узнать проигрывается ли данный поток сейчас:
sound->isPlaying();
Узнать текущую громкость у данного потока:
sound->getVolume();
Установить панораму звука (слева, по центру, справа):
sound->setPan(-1.0);//в данном случае установит звук на левый канал, 0.0 - установит посередине, а 1.0 справа
Установить скорость воспроизведения звука (тональность тоже меняется):
sound->setPitchShift(1.0);//нормальная скорость. Значения от 0.5 до 1.0 замедлят звук, а от 1.0 до 2.0 ускорят.
sound->getPitchShift();//узнать текущее значение PitchShift для потока
В заголовочном файле «audiere.h» определены ещё некоторые другие функции такие, как «CreateTone();», «CreatePinkNoise()» и прочие, включая MIDI-возможности. Список членов пространства имён «audiere», а заодно и ссылка на онлайн-документацию здесь.
Конечно же, в нашу программу ещё нужно добавить обработку ошибок, тогда исходный код будет выглядеть следующим образом:
AudioDevicePtr device = OpenDevice();
if(!device)
{
cout<<"Ошибка открытия AudioDevice. Нажмите любую клавишу для выхода..";
getche();
return 0; //выходим из программы
}
А также обработка ошибки открытия файла:
if(!sound){
cout<<"Ошибка открытия файла! Для выхода нажмите любую клавишу..";
getche();
return 0;
}
#include <iostream> //нужен для вывода строк "cout<<"
#include "conio.h" //нужен намеренно для "getche()" , а не "cin>>"
#include "windows.h" //библиотека audiere её требует
#include "audiere.h" //сама библиотека
using namespace std;
using namespace audiere; //определяем пространства имён для более короткой записи кода
int main()
{
setlocale(0, "Russian"); //пусть наша консоль говорит по-русски
cout<<"Простейшее воспроизведение звука"<<endl;
AudioDevicePtr device = OpenDevice(); //Для начала нужно открыть AudioDevice
if(!device){
cout<<"Ошибка открытия AudioDevice. Нажмите любую клавишу для выхода..";
getche();
return 0; //выходим из программы
}
OutputStreamPtr sound = OpenSound(device , "sound.wav" , false); //открываем наш звук
if(!sound){
cout<<"Ошибка открытия файла! Для выхода нажмите любую клавишу..";
getche();
return 0;
}
sound->play(); //проигрываем наш звук
getche(); //ждём нажатия любой клавиши прежде чем выйти из программы
}
И напоследок, программа по-интереснее: сделаем примитивный музыкальный инструмент!
В этот раз мы будем пользоваться методом «getch()». Его отличие в том, что он работает также, как «getche()», но не отображает введенные символы. Но вдруг у вас получилась интересная мелодия и нужно посмотреть, что вы нажимали?: можно использовать и «getche()», а можно и в массив записывать с «getch()». Я намеренно не усложняю текст для новичков, чтобы не скрывать простоту кода, поэтому проверку на ошибки и всё остальное вы можете дописать сами.
Исходный код музыкального инструмента:
#include <iostream>
#include "conio.h"
#include "windows.h"
#include "audiere.h"
using namespace std;
using namespace audiere;
int main()
{
setlocale(0, "Russian");
cout << "Играйте клавишами Q W E R T Y U I O . X - для выхода" << endl;
AudioDevicePtr device = OpenDevice();
OutputStreamPtr do1 = OpenSound(device , "do.wav" , false); //здесь мы начинаем создание потоков со звуками определённой высоты
OutputStreamPtr re = OpenSound(device , "re.wav" , false);
OutputStreamPtr mi = OpenSound(device , "mi.wav" , false);
OutputStreamPtr fa = OpenSound(device , "fa.wav" , false);
OutputStreamPtr sol = OpenSound(device , "sol.wav" , false);
OutputStreamPtr la = OpenSound(device , "la.wav" , false);
OutputStreamPtr si = OpenSound(device , "si.wav" , false);
OutputStreamPtr do2 = OpenSound(device , "do2.wav" , false); //заканчиваем октавой - вновь нота до, но уже следующей октавы
char notePlay = '1'; //инициализируем символьную переменную с произвольным значением
while(notePlay!='x') //цикл выполняется, пока не нажата клавиша "x"
{
notePlay=getch();
if(notePlay=='q') do1->play();
else if(notePlay=='w') re->play();
else if(notePlay=='e') mi->play();
else if(notePlay=='r') fa->play();
else if(notePlay=='t') sol->play();
else if(notePlay=='y') la->play();
else if(notePlay=='u') si->play();
else if(notePlay=='i') do2->play();
}
return 0;
}
Файлы *.wav для этого проекта можно скачать здесь. Распакуйте их в папку с исходным кодом.
char inputVar;
inputVar=getche();
Но как видишь ты сможешь нажать на клавишу лишь однажды, поэтому этот метод лучше использовать для массивов в циклах:
char inputVar[30]; //наша строка-массив
int i=0; //счётчик для функции
while(!inputVar[i]=='\r' && i<30)
{
inputVar[i]=getche();
i++;
}
" !inputVar[i]=='\r' " — это проверка на нажатие «Enter», если он будет нажат — цикл закончится. '\r' — это признак возврата каретки.
А теперь, почему в коде «getche()» стоит так одиноко и не присваивается никакой переменной: нам это не нужно. Нужно лишь дождаться нажатия любой клавиши, после чего программа завершится.
С помощью «setlocale(0, „Russian“);» устанавливается поддержка вывода русского текста в консоль (но не ввода).
Следующие две строки будут понятнее после более продолжительного знакомства с C++, например, по книге
Герберт Шилдт — «Полный справочник по C++»
Поскольку «sound» у нас — это указатель, то методы для него будут выполняться с помощью оператора стрелочки "->", а не точки; как могло бы быть: «sound.play()». Этому, в вышеупомянутой книге, посвящена глава «Указатели».
Комментарий к конструкции «if else»:
Для всех следующих проверок мы использовали «else if», что даёт прирост скорости для программы, потому что после проверки каждого значения и его соответствия нажатой клавишы — остальные опреаторы else if выполнены не будут. Если бы мы записали:
while(notePlay!='x') //цикл выполняется, пока не нажата клавиша "x"
{
notePlay=getch();
if(notePlay=='q') do1->play();
if(notePlay=='w') re->play();
if(notePlay=='e') mi->play();
if(notePlay=='r') fa->play();
if(notePlay=='t') sol->play();
if(notePlay=='y') la->play();
if(notePlay=='u') si->play();
if(notePlay=='i') do2->play();
}
то несмотря, на нажатую, например, клавишу 'q' — все остальные условия всё равно бы проверялись, что в данном случае бессмысленно.
Желаю успеха в обучении!
Пусть этот краткий обзор послужит началом для новичков в их замыслах. Всего доброго!
Комментарии (22)
gbg
27.12.2016 20:05Может, стоило все же использовать массивы, а не вываливать на читателя китайский код.
Genoik
28.12.2016 01:29+2У меня есть почему-то стойкое ощущение что подобная статья не совсем для Хабра…
Вопрос к автору, раз уж вы решили в цикле проверять нажатие клавиш, то почему у вас прописано:
if(notePlay=='q') do1->play(); if(notePlay=='w') re->play(); if(notePlay=='e') mi->play(); if(notePlay=='r') fa->play(); if(notePlay=='t') sol->play(); if(notePlay=='y') la->play(); if(notePlay=='u') si->play(); if(notePlay=='i') do2->play();
а не:
if(notePlay=='q') do1->play(); else if(notePlay=='w') re->play(); else if(notePlay=='e') mi->play(); else if(notePlay=='r') fa->play(); else if(notePlay=='t') sol->play(); else if(notePlay=='y') la->play(); else if(notePlay=='u') si->play(); else if(notePlay=='i') do2->play();
Статья подается как учебный материал, но учит не очень хорошему стилю.
А вообще я бы посоветовал использовать switch в подобных случаях.BratSinot
28.12.2016 02:26+2И ещё полное отсутствие форматирования. Вот из-за этого и существует gofmt. Мало кто из новичков, задумывается о хорошем форматировании.
Genoik
28.12.2016 01:36+1Еще мне кажется у вас ошибка в коде:
char inputVar[30]; //наша строка-массив int i=0; //счётчик для функции while(!inputVar[i]=='\r' && i<100) { inputVar[i]=getche(); i++; }
Вы создаете массив на 30 элементов, но вот счетчик у вас почему-то до 100.
P.S. Интересно, кто-нибудь догадается на Хабр написать статью про написание HelloWord на С++…
Genoik
28.12.2016 01:48+1Еще один вопрос автору, зачем делать вот это:
файл «audiere.lib» в папку «lib» компилятора, а заголовочник «audiere.h» также в папку «include» вашего компилятора
если честно, не совсем понятна логика сего действа. В современном мире есть IDE, которые не позволяют подключить библиотеку к проекту и надо все используемые библиотеки и заголовочные файлы копировать туда, где расположены файлы стандартной библиотеки?
А какой конкретно компилятор вы имели ввиду? Может есть менее экзотические способы подключать библиотеки ?!
Silentfog
28.12.2016 03:31-1для нас с Вами это очевидные вещи, но это «helloworld» для звука. Я ориентировал её на тех, кто возможно ни разу ещё не подключал сторонних библиотек.Пусть Ваш комментарий и будет дополнением к подключению библиотек
Genoik
28.12.2016 12:40+1Ну как бы выразиться поточнее…
Дело не в том, очевидные это вещи или нет. Дело в том, что вы учите не совсем правильному подходу. Я не против как таковых статей для новичков, я против того, чтобы этих новичков учили неправильным вещам. Переучивать их потом выходит дороже, чем учить с нуля.
И если вы позиционируете статью как учебную, тогда вам вопрос от новичка, где человек должен искать у себя на ПК папку с компилятором? Вы ведь не показываете пример работы в какой-то конкретной среде, я могу использовать VisualStudio, могу использовать связку Qt+MinGW и т.д.
Так как новички обычно не устанавливают компилятор вручную, а ставят сразу какую-нибудь IDE, мне лично кажется что процесс поиска папки, где расположены стандартные библиотеки компилятора, будет для них не совсем тривиальным, и скорее всего они полезут в Гугл. А если они полезут в Гугл, зачем нужна ваша статья?
Мало того, что в самом коде есть ошибки, так и в ней нет каких-то особенностей, относящихся конкретно к Audiere, поменяй имя библиотеки с Audiere на любое другое имя и 80% статьи останется без изменений.Silentfog
29.12.2016 01:24-1Хочу выразить одну мысль, хотелось бы узнать Ваше видение.
Хабрахабр имеет возможность оставлять комментарии проверенных пользователей, которые, по-видимому по логике здесь уже находятся с чёткой целью — совершенствовать способности. Из рационального подхода и всем искренним желанием своего сердца, я всё же, надеюсь, что мы не будем учитывать некоторый процент самоутверждения среди пользователей, когда мы занимаемся бессмысленными обсуждениями или мыслями, без которых можно обойтись.
Теперь после предисловия, сама мысль: я думаю, вернее будет использовать статьи, как предмет потенциально незаконченный (иначе бы здесь не было возможности редактирования), а как предмет с редакцией. Я думаю, комментарии под статьёй в первую очередь должны быть направлены на пополнение статьи, обогащение её опытом каждого. В конце концов, нет более правильного способа сделать что-то хорошо, кроме как улучшить, то что сделано недостаточно хорошо. Есть редкие случаи когда не следует улучшать то, что не способно заработать — но это чаще всего уже определено в момент создания. Если бы мы, как люди, направившие общее устремление к движению к гипотетической, но силой важной — к истине, и были ювелирами мысли, то я думаю многие предметы, включая подобные статьи стали бы гораздо эффективнее. И у меня к Вам вопрос, я уверен, что когда-то Вы сталкивались с резким отношением к своим мысленным рассуждениям. Чаще всего критическое отношение имеет ключ «Нет, это не нужно.». Вы наверно задумывались, что созиданием можно было бы сделать куда больше, чем пресекать даже попытки что-то изложить. Мне нравится пример некоторых русских классических литературных критиков: в их критических статьях они не рубили с плеча рассматривая рассказы и их авторов, а были глубоко вовлечены в их становление и движение к усовершенствованию, были соучаствовавшими в их достижении мастерства.
В послесловии Вас хотел бы поблагодарить за критические дополнения. Думаю, (нам ведь есть чему учиться ) нам нужно немножко менять отношение от критических оценок, всё-таки это не работает и не помогает.Genoik
29.12.2016 21:34Если вопрос именно ко мне, то я честно говоря его не понял. Вы не могли бы сформулировать свою мысль более кратко.
Вы хотите чтобы какую-то не очень удачную (я сознательно избегаю слово плохую) статью в комментариях за вас дописывали пользователи? Этакий аналог вики, когда вы пишете что-то, вас поправляют в комментариях, вы переписываете статью?
Если вам интересно мое мнение, то я против этого. Мне кажется будет полный бардак. Сейчас не редкость, когда комментарии интереснее самой статьи, но это часто происходит само-собой, а вы по факту предлагаете это поставить на поток. Если конечно я вас правильно понял.Silentfog
30.12.2016 04:00Думаю здесь ключевая ошибка в концепции, что что-то принадлежит мне или ему, у меня есть глубокое убеждение, что переход во всеобщее достояние имеет в перспективе более полную свободу для совершенства и пользы для человечества, нежели желание иметь собственность. Но это я лишь предполагаю, ошибается всякий. Мне кажется, что в вики это довольно глубокая идея обобщения всеобщего опыта. По поводу бардака — думаю есть вероятность, что нынешний вариант это не менее хаотичное и разбросанное качество организации статей. Та статья, которая была написана несколько лет назад и уже устарела — больше уже не перепишется, не обновится, не исправится. Всё-таки во всём должны существовать формы, если бы их не было, то, например музыка была бы лишь чередованием несвязности. Также и научный и публицистический материал должен быть организован в формы, например энциклопедии. Есть возможности обновлять, совершенстовать форму — и энциклопедия в этом тоже ещё может измениться. Но у энциклопедичности есть минус несомненный — данная форма лишает индивидуальности, соответственно статьи бы здесь потеряли налёт человеческого обличия.
Получается, что подобие «гонзо-журналистики» — добавляет приятный оттенок живой истории или рассказа, в ущерб энциклопедичности; а энциклопедичность, имея наиболее совершенную форму в передаче фактической информации, становится холодным бездушным текстом. Выходит, что подобные статьи, как у меня, и лишенные энциклопедичности — это тот возможный процент, где у этой концепции имеются минусы и позволяют появляться определенному проценту незавершенных статей.
В конце концов, в корне лежит простое человеческое желание чем-то поделиться, радостью творчества или открытия. Когда-то мне очень хотелось бы даже подобной статьи, но её не было. Статьи ориентированные на новичков часто переполнены излишками иной информации, хотя несомненно нужной в перспективе. И когда ты всего лишь хочешь сделать винт для самолёта, тебе рассказывают как построить весь самолёт. И таким образом статьи в которых указаны мельчайшие нюансы, вызывают перегрузку информацией и замедляют процесс обучения. Я однажды пробовал читать Кантора и его теорию множеств — и конечно же из этого ничего не вышло. Обучающийся, если он на самом деле учится — обучится, и отточит всё что нужно. У меня есть мысль, что так часто упоминающееся заучивание плохого стиля кода или иных механических повторений — свойственно тем, кто в сути и не обучается, а лишь подстраивается под выполнение определенных требований. Человек, цель которого решить задачу и получить за неё хорошую оценку (не вылететь с работы) — никогда не задумается ни о каком стиле, или лучшем алгоритме. В таком смысле, под редакцией статьи я лишь подразумевал желание человека учиться, принимать свои ошибки, перестать подпитывать собственное самоутверждение; а со стороны иных людей — желание помочь, а не изобличить, действие — а не оценочная критика, перестать относиться друг к другу в соревновательной концепции и не давать ход ко взаимному унижению. Вся эта система собственничества и самоутверждения в социуме ведет лишь к деградации моральных аспектов человека, людям недостаёт простоты, равнодушие и отношение друг к другу как к лишь безжизненным механизмам усиливается, мы резко настроены против друг друга и скпетицизм используем не для движения к чему-то наиболее верному, а на самом деле для того, чтобы нас не пошатнули. Мне бы хотелось, чтобы люди помогали друг другу, учит всегда лишь собственный пример. Один строитель видит камень у основания непрочный — и меняет его, а не ищет виноватых показывая как сейчас рухнет дом. Он показывает как его сохранить. Всё же я думаю есть, что можно ещё улучшить в наших способах делиться информацией в интернете и обучаться, многое работает не достаточно хорошо и это можно менять.Genoik
30.12.2016 13:02Я понимаю вашу мысль, но давайте ее продолжим так. Что, если бы читатели могли дописывать книги или вносить в них исправления? И в журналы бы отправляли свое видение, как должна выглядеть статья по их мнению.
Статья или роман тем и отличается от вики, что это законченное произведение.
А так возможно один читатель захотел бы, чтоб Анна Каренина не бросилась под поезд, а повесилась, другой бы захотел, чтоб она выжила и вышло еще 15 книг про ее жизнь и т.д. В этом случае вы, как автор, не несете никакой ответственности за содержание статьи.
Возьмем даже текущую статью, первоначально в переборе нажатых кнопок было использованы условия if. Я сказал, что в данном случае, если уж так хочется использовать if, стоит использовать else if. Но, я также по прежнему считаю, что в данном случае необходимо использовать switch. Будем править статью еще раз?
А придет другой, и скажет, что ему else if привычнее. Что будем делать? На каждую статью назначать редактора, который будет выбирать наиболее правильное, с его точки зрения, решение? На вики ведь так и происходит, статьи правятся редакторами.
Мне кажется идея несколько утопическая.
Genoik
30.12.2016 13:12Относительно обучения.
Мне кажется это процесс индивидуальный.
Лично я критику воспринимаю вполне спокойно, и если ко мне подходит человек и обосновано говорит что все, что я написал это полная фигня и все надо переписать, потому-то и потому-то, я это нормально воспринимаю и благодарен ему за это, потому что на этом и строиться процесс обучения.
Ведь в школе вам ставят вполне спокойно 2 или 3, а не только 5, ради того, чтобы у вас не пропало желание учиться. Я лично всегда был против натягивания каких-либо оценок.
Относительно этой конкретной статьи, я лично удивлен, что вы ее когда-то хотели увидеть, запрос в гугл: «как подключить стороннюю библиотеку. С++» выдаст вам кучу таких же статей.
jaiprakash
28.12.2016 10:05sound->setPan(-1,0);
Здесь именно 2 аргумента, или надо было так:
sound->setPan(-1.0);
Vjatcheslav3345
28.12.2016 11:28С точки зрения перспективы Ваш открытый проект можно преобразовать в программу-тьютор.
Сейчас есть открытые видео- аудио- редакторы, компьютерные игры, много иных программ, даже системы проверки программ в спортивном программировании — а вот из программ, обучающих программировать я знаю только одну — AdaTutor.
С учётом того, что в вашем проекте можно будет обучать С и С++, популярность такой программы будет куда выше чем программы для языка Ada.
eastpak
06.01.2017 14:52К сожалению, Audiere уже очень давно не поддерживается и поэтому ее будет очень тяжело использовать в серьезных проектах. Мы раньше ее использовали в нашем игровом движке. Когда делали вещи более сложные чем простые play/stop/pause возникали проблемы. Пришлось копать код Audiere и вносить мелкие правки. Но чем более активно пользовались библиотекой, тем больше появлялось проблем и чтобы их править нужно уже было тратить значительное количество времени, чтобы раскопать что же происходит внутри Audiere. В конце концов перешли на связку SFML.Audio + OpenAL Soft — больше проблем с аудио не знаем.
BlackJet
хорошая библиотека, использовал её давно для игры. единственное нарекание — при цикличном воспроизведении ogg файла через некоторое время музыка «замедлялась». и, емнип поддержка и разработка давно прекращена. поправьте, если ситуация изменилась.