вторник, 13 марта 2012 г.

Воспроизведение звука в Qt

Qt предоставляет три пути для воспроизведения звука.
  1. Класс QSound
  2. Класс QAudioOutput
  3. Модуль QtPhonon
Самым удобным кажется класс QSound. Достаточно вызвать статическую функцию класса play(const QString & filename) для проигрывания файла filename. Воспроизводимый формат - wav. Но у QSound есть недостаток - он не умеет воспроизводить файлы из ресурсов. Об этом прямо написано в документации последней версии (4.8) 
Note that QSound does not support resources. This might be fixed in a future Qt version.
Поэтому, если захочется хранить ваши звуки в ресурсах, ничего не получится. Выход, конечно, есть - написать костыли. А именно - скидывать файл из ресурсов во временную папку и воспроизводить уже оттуда.

Вторым методом является класс QAudioOutput.

Класс позволяет отправить аудио данные на выходное аудиоустройство. На вашу звуковую плату. Стандартно воспроизводит файлы формата "audio/pcm" - Linear PCM. По сути - те же wav. Требует детального описания воспроизводимого файла, указания частоты, канала, размера сэмпла. На вход подается QIODevice, поэтому можно подать QBuffer, т.е. можно воспроизводить файл из ресурсов.Небольшой пример.
QFile inputFile;
inputFile.setFileName("test.wav");
inputFile.open(QIODevice::ReadOnly);

QAudioFormat format;
// Set up the format, eg.
format.setFrequency(44100);
format.setChannels(2);
format.setSampleSize(16);
format.setCodec("audio/pcm");

QAudioOutput *audio = new QAudioOutput( format, 0);
audio->start(&inputFile);
 Но у данного метода есть проблема, с которой я так и не разобрался. При воспроизведении файла четко слышны посторонние щелчки, особенно в начале и конце воспроизведения. Как оказалось не у меня одного. Разбираться было лениво и метод отправился на помойку.

 Остался QtPhonon. Мультимедийный фреймворк для воспроизведения аудио и видео.
Подключается к проекту так:
QT += phonon
В examples Qt есть пример Music Player Example.
В нем подробно рассматривается работа с Phonon. Воспроизводит mp3, wav, ogg. Грузит для этого кодеки, чем притормаживает работу программы. Может воспроизводить из ресурсов. Мне не понравилось из-за тормозов с загрузкой кодеков.
Поэтому остановился на QSound. Звуки пришлось выложить наружу.

5 комментариев:

  1. QAudioOutput криво работает на Qt5.1 (https : // bugreports . qt-project . org/browse/QTBUG-30345) и если глянешь доки - то не найдешь у него методов setFrequency и setChannels (которые используются в твоем примере)

    QSound у меня вобщем тоже не работает (вроде как известная проблема с кодеками), и, судя по обсуждениям (я не смог проверить, т.к. не работает) проблема там с проигрыванием одновременно нескольких файлов.

    Фонон не работает на андройдах (и, вроде бы, в ближайшее время его там не планируется).

    У меня работает нормально только QMediaPlayer, но он тоже не работает с ресурсами и, судя по описанию, никогда не будет.

    ОтветитьУдалить
  2. // format.setFrequency(44100); заменить на:
    format.setSampleRate(44100);
    // format.setChannels(2);
    format.setChannelCount(2);
    И всё работает, но пока разобрался только как wav воспроизводить ...

    ОтветитьУдалить
  3. У меня вылетает после audio->start(&inputFile) :(

    ОтветитьУдалить
  4. >>При воспроизведении файла четко слышны посторонние щелчки, особенно в начале и конце воспроизведения.
    Ну ещё бы. В wav файле кроме собственно аудиопотока есть ещё заголовок (вначале) и информация для навигации по файлу (в конце). Они и дают щелчки.
    Нужно вручную разбирать wav файл на куски и скармливать в QAudioOutput чистый звук.

    ОтветитьУдалить
  5. Возможно пригодиться кому на PyQt5

    import sys
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtMultimedia import QAudioOutput, QAudioFormat
    from PyQt5.QtCore import QFile, QIODevice

    if __name__ == '__main__':

    app=QApplication(sys.argv)

    _file = 'C://_QSoundTest_simple//msg14.wav'

    soundFile=QFile()
    soundFile.setFileName(_file)

    _discret = 29000
    format = QAudioFormat()
    format.setChannelCount(1)
    format.setSampleRate(_discret)
    format.setSampleSize(16)
    format.setCodec("audio/pcm")
    format.setByteOrder(QAudioFormat.LittleEndian)
    format.setSampleType(QAudioFormat.SignedInt)

    output=QAudioOutput(format)
    soundFile.open(QIODevice.ReadOnly)
    output.start(soundFile)

    app.exec_()

    ОтветитьУдалить