Приветствую! Данная заметка ориентирована на начинающих программистов, самых, что ни на есть новичков. Она о простой библиотеке Audiere. Если вы когда-то хотели вывести звук просто и быстро, то Audiere вам скорее всего понравится!

Для начала расскажу немного о том, что это:

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-файлом нашей программы.

Если совсем новичок
Если ты третий день, как научился выводить «cout<<», то заранее скажу, друг, просто повторяй, что написано внизу, я постараюсь всё объяснить.

  • Необходимо подключить заголовочные файлы:

#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 для этого проекта можно скачать здесь. Распакуйте их в папку с исходным кодом.

А это для совсем новичков
В «conio.h» есть хорошая альтернатива методу «cin>>» — это «getche()». «getche()» не дожидается ввода команды «Enter», а присваивает значение переменной сразу после нажатия клавиши:

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)


  1. BlackJet
    27.12.2016 17:21

    хорошая библиотека, использовал её давно для игры. единственное нарекание — при цикличном воспроизведении ogg файла через некоторое время музыка «замедлялась». и, емнип поддержка и разработка давно прекращена. поправьте, если ситуация изменилась.


  1. gbg
    27.12.2016 20:05

    Может, стоило все же использовать массивы, а не вываливать на читателя китайский код.


  1. Refridgerator
    27.12.2016 20:40

    В чём преимущество перед другими библиотеками, например PortAudio?


  1. 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 в подобных случаях.


    1. BratSinot
      28.12.2016 02:26
      +2

      И ещё полное отсутствие форматирования. Вот из-за этого и существует gofmt. Мало кто из новичков, задумывается о хорошем форматировании.


    1. Silentfog
      29.12.2016 00:47

      По поводу else if.


    1. Silentfog
      29.12.2016 04:15

      это существенная ошибка, благодарю, исправлено.


  1. 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 на С++…


    1. Silentfog
      28.12.2016 03:29

      благодарю, поправил!


  1. Genoik
    28.12.2016 01:48
    +1

    Еще один вопрос автору, зачем делать вот это:

    файл «audiere.lib» в папку «lib» компилятора, а заголовочник «audiere.h» также в папку «include» вашего компилятора
    

    если честно, не совсем понятна логика сего действа. В современном мире есть IDE, которые не позволяют подключить библиотеку к проекту и надо все используемые библиотеки и заголовочные файлы копировать туда, где расположены файлы стандартной библиотеки?

    А какой конкретно компилятор вы имели ввиду? Может есть менее экзотические способы подключать библиотеки ?!


  1. Silentfog
    28.12.2016 03:31
    -1

    для нас с Вами это очевидные вещи, но это «helloworld» для звука. Я ориентировал её на тех, кто возможно ни разу ещё не подключал сторонних библиотек.Пусть Ваш комментарий и будет дополнением к подключению библиотек


    1. Genoik
      28.12.2016 12:40
      +1

      Ну как бы выразиться поточнее…
      Дело не в том, очевидные это вещи или нет. Дело в том, что вы учите не совсем правильному подходу. Я не против как таковых статей для новичков, я против того, чтобы этих новичков учили неправильным вещам. Переучивать их потом выходит дороже, чем учить с нуля.

      И если вы позиционируете статью как учебную, тогда вам вопрос от новичка, где человек должен искать у себя на ПК папку с компилятором? Вы ведь не показываете пример работы в какой-то конкретной среде, я могу использовать VisualStudio, могу использовать связку Qt+MinGW и т.д.
      Так как новички обычно не устанавливают компилятор вручную, а ставят сразу какую-нибудь IDE, мне лично кажется что процесс поиска папки, где расположены стандартные библиотеки компилятора, будет для них не совсем тривиальным, и скорее всего они полезут в Гугл. А если они полезут в Гугл, зачем нужна ваша статья?

      Мало того, что в самом коде есть ошибки, так и в ней нет каких-то особенностей, относящихся конкретно к Audiere, поменяй имя библиотеки с Audiere на любое другое имя и 80% статьи останется без изменений.


      1. Silentfog
        29.12.2016 01:24
        -1

        Хочу выразить одну мысль, хотелось бы узнать Ваше видение.

        Хабрахабр имеет возможность оставлять комментарии проверенных пользователей, которые, по-видимому по логике здесь уже находятся с чёткой целью — совершенствовать способности. Из рационального подхода и всем искренним желанием своего сердца, я всё же, надеюсь, что мы не будем учитывать некоторый процент самоутверждения среди пользователей, когда мы занимаемся бессмысленными обсуждениями или мыслями, без которых можно обойтись.

        Теперь после предисловия, сама мысль: я думаю, вернее будет использовать статьи, как предмет потенциально незаконченный (иначе бы здесь не было возможности редактирования), а как предмет с редакцией. Я думаю, комментарии под статьёй в первую очередь должны быть направлены на пополнение статьи, обогащение её опытом каждого. В конце концов, нет более правильного способа сделать что-то хорошо, кроме как улучшить, то что сделано недостаточно хорошо. Есть редкие случаи когда не следует улучшать то, что не способно заработать — но это чаще всего уже определено в момент создания. Если бы мы, как люди, направившие общее устремление к движению к гипотетической, но силой важной — к истине, и были ювелирами мысли, то я думаю многие предметы, включая подобные статьи стали бы гораздо эффективнее. И у меня к Вам вопрос, я уверен, что когда-то Вы сталкивались с резким отношением к своим мысленным рассуждениям. Чаще всего критическое отношение имеет ключ «Нет, это не нужно.». Вы наверно задумывались, что созиданием можно было бы сделать куда больше, чем пресекать даже попытки что-то изложить. Мне нравится пример некоторых русских классических литературных критиков: в их критических статьях они не рубили с плеча рассматривая рассказы и их авторов, а были глубоко вовлечены в их становление и движение к усовершенствованию, были соучаствовавшими в их достижении мастерства.

        В послесловии Вас хотел бы поблагодарить за критические дополнения. Думаю, (нам ведь есть чему учиться ) нам нужно немножко менять отношение от критических оценок, всё-таки это не работает и не помогает.


        1. Genoik
          29.12.2016 21:34

          Если вопрос именно ко мне, то я честно говоря его не понял. Вы не могли бы сформулировать свою мысль более кратко.
          Вы хотите чтобы какую-то не очень удачную (я сознательно избегаю слово плохую) статью в комментариях за вас дописывали пользователи? Этакий аналог вики, когда вы пишете что-то, вас поправляют в комментариях, вы переписываете статью?
          Если вам интересно мое мнение, то я против этого. Мне кажется будет полный бардак. Сейчас не редкость, когда комментарии интереснее самой статьи, но это часто происходит само-собой, а вы по факту предлагаете это поставить на поток. Если конечно я вас правильно понял.


          1. Silentfog
            30.12.2016 04:00

            Думаю здесь ключевая ошибка в концепции, что что-то принадлежит мне или ему, у меня есть глубокое убеждение, что переход во всеобщее достояние имеет в перспективе более полную свободу для совершенства и пользы для человечества, нежели желание иметь собственность. Но это я лишь предполагаю, ошибается всякий. Мне кажется, что в вики это довольно глубокая идея обобщения всеобщего опыта. По поводу бардака — думаю есть вероятность, что нынешний вариант это не менее хаотичное и разбросанное качество организации статей. Та статья, которая была написана несколько лет назад и уже устарела — больше уже не перепишется, не обновится, не исправится. Всё-таки во всём должны существовать формы, если бы их не было, то, например музыка была бы лишь чередованием несвязности. Также и научный и публицистический материал должен быть организован в формы, например энциклопедии. Есть возможности обновлять, совершенстовать форму — и энциклопедия в этом тоже ещё может измениться. Но у энциклопедичности есть минус несомненный — данная форма лишает индивидуальности, соответственно статьи бы здесь потеряли налёт человеческого обличия.

            Получается, что подобие «гонзо-журналистики» — добавляет приятный оттенок живой истории или рассказа, в ущерб энциклопедичности; а энциклопедичность, имея наиболее совершенную форму в передаче фактической информации, становится холодным бездушным текстом. Выходит, что подобные статьи, как у меня, и лишенные энциклопедичности — это тот возможный процент, где у этой концепции имеются минусы и позволяют появляться определенному проценту незавершенных статей.
            В конце концов, в корне лежит простое человеческое желание чем-то поделиться, радостью творчества или открытия. Когда-то мне очень хотелось бы даже подобной статьи, но её не было. Статьи ориентированные на новичков часто переполнены излишками иной информации, хотя несомненно нужной в перспективе. И когда ты всего лишь хочешь сделать винт для самолёта, тебе рассказывают как построить весь самолёт. И таким образом статьи в которых указаны мельчайшие нюансы, вызывают перегрузку информацией и замедляют процесс обучения. Я однажды пробовал читать Кантора и его теорию множеств — и конечно же из этого ничего не вышло. Обучающийся, если он на самом деле учится — обучится, и отточит всё что нужно. У меня есть мысль, что так часто упоминающееся заучивание плохого стиля кода или иных механических повторений — свойственно тем, кто в сути и не обучается, а лишь подстраивается под выполнение определенных требований. Человек, цель которого решить задачу и получить за неё хорошую оценку (не вылететь с работы) — никогда не задумается ни о каком стиле, или лучшем алгоритме. В таком смысле, под редакцией статьи я лишь подразумевал желание человека учиться, принимать свои ошибки, перестать подпитывать собственное самоутверждение; а со стороны иных людей — желание помочь, а не изобличить, действие — а не оценочная критика, перестать относиться друг к другу в соревновательной концепции и не давать ход ко взаимному унижению. Вся эта система собственничества и самоутверждения в социуме ведет лишь к деградации моральных аспектов человека, людям недостаёт простоты, равнодушие и отношение друг к другу как к лишь безжизненным механизмам усиливается, мы резко настроены против друг друга и скпетицизм используем не для движения к чему-то наиболее верному, а на самом деле для того, чтобы нас не пошатнули. Мне бы хотелось, чтобы люди помогали друг другу, учит всегда лишь собственный пример. Один строитель видит камень у основания непрочный — и меняет его, а не ищет виноватых показывая как сейчас рухнет дом. Он показывает как его сохранить. Всё же я думаю есть, что можно ещё улучшить в наших способах делиться информацией в интернете и обучаться, многое работает не достаточно хорошо и это можно менять.


            1. Genoik
              30.12.2016 13:02

              Я понимаю вашу мысль, но давайте ее продолжим так. Что, если бы читатели могли дописывать книги или вносить в них исправления? И в журналы бы отправляли свое видение, как должна выглядеть статья по их мнению.
              Статья или роман тем и отличается от вики, что это законченное произведение.
              А так возможно один читатель захотел бы, чтоб Анна Каренина не бросилась под поезд, а повесилась, другой бы захотел, чтоб она выжила и вышло еще 15 книг про ее жизнь и т.д. В этом случае вы, как автор, не несете никакой ответственности за содержание статьи.

              Возьмем даже текущую статью, первоначально в переборе нажатых кнопок было использованы условия if. Я сказал, что в данном случае, если уж так хочется использовать if, стоит использовать else if. Но, я также по прежнему считаю, что в данном случае необходимо использовать switch. Будем править статью еще раз?
              А придет другой, и скажет, что ему else if привычнее. Что будем делать? На каждую статью назначать редактора, который будет выбирать наиболее правильное, с его точки зрения, решение? На вики ведь так и происходит, статьи правятся редакторами.
              Мне кажется идея несколько утопическая.


            1. Genoik
              30.12.2016 13:12

              Относительно обучения.
              Мне кажется это процесс индивидуальный.
              Лично я критику воспринимаю вполне спокойно, и если ко мне подходит человек и обосновано говорит что все, что я написал это полная фигня и все надо переписать, потому-то и потому-то, я это нормально воспринимаю и благодарен ему за это, потому что на этом и строиться процесс обучения.
              Ведь в школе вам ставят вполне спокойно 2 или 3, а не только 5, ради того, чтобы у вас не пропало желание учиться. Я лично всегда был против натягивания каких-либо оценок.
              Относительно этой конкретной статьи, я лично удивлен, что вы ее когда-то хотели увидеть, запрос в гугл: «как подключить стороннюю библиотеку. С++» выдаст вам кучу таких же статей.


              1. Silentfog
                31.12.2016 17:31

                С Новым Годом :)


  1. jaiprakash
    28.12.2016 10:05

    sound->setPan(-1,0);
    

    Здесь именно 2 аргумента, или надо было так:

    sound->setPan(-1.0);
    


    1. Silentfog
      29.12.2016 00:31

      поправил!


  1. Vjatcheslav3345
    28.12.2016 11:28

    С точки зрения перспективы Ваш открытый проект можно преобразовать в программу-тьютор.
    Сейчас есть открытые видео- аудио- редакторы, компьютерные игры, много иных программ, даже системы проверки программ в спортивном программировании — а вот из программ, обучающих программировать я знаю только одну — AdaTutor.
    С учётом того, что в вашем проекте можно будет обучать С и С++, популярность такой программы будет куда выше чем программы для языка Ada.


  1. eastpak
    06.01.2017 14:52

    К сожалению, Audiere уже очень давно не поддерживается и поэтому ее будет очень тяжело использовать в серьезных проектах. Мы раньше ее использовали в нашем игровом движке. Когда делали вещи более сложные чем простые play/stop/pause возникали проблемы. Пришлось копать код Audiere и вносить мелкие правки. Но чем более активно пользовались библиотекой, тем больше появлялось проблем и чтобы их править нужно уже было тратить значительное количество времени, чтобы раскопать что же происходит внутри Audiere. В конце концов перешли на связку SFML.Audio + OpenAL Soft — больше проблем с аудио не знаем.