Опубликован: 13.07.2012 | Доступ: свободный | Студентов: 460 / 9 | Оценка: 5.00 / 5.00 | Длительность: 18:06:00
Специальности: Программист
Лекция 19:

Мультимедиа. Работа со звуком

< Лекция 18 || Лекция 19: 12345 || Лекция 20 >

Обратите внимание, что при завершении работы нашего приложения необходимо закрыть аудио-устройство и удалить вызов аудио с помощью методов void AudioDeviceManager::closeAudioDevice() и void AudioDeviceManager::removeAudioCallback(AudioIODeviceCallback* callback). Кроме того, необходимо обнулить объявленные указатели ( пример 19.3).

TCentralComponent::~TCentralComponent()
{
  pAudioDeviceManager->closeAudioDevice();
  TransportSource.setSource(0);
  AudioPlayer.setSource(0);
  pAudioDeviceManager->removeAudioCallback(& AudioPlayer);
  if(pAudioDeviceManager) delete pAudioDeviceManager;
  if(pCurrentAudioFileSource) delete pCurrentAudioFileSource;
  if(pFileNameDialog) delete pFileNameDialog;
  deleteAllChildren();
} 
Листинг 19.3. Реализация деструктора класса компонента содержимого TCentralComponent (файл TCentralComponent.cpp)

Наша программа будет менять цвет и текст кнопки pPlayButton в зависимости от того, идёт ли воспроизведение аудио-файла, или оно остановлено ( пример 19.4). Узнать, осуществляется ли воспроизведение в текущий момент, позводяет метод bool AudioTransportSource::isPlaying() const throw().

void TCentralComponent::changeListenerCallback(ChangeBroadcaster*)
{
  // Если идёт воспроизведение...
  if(TransportSource.isPlaying())
  {
    pPlayButton->setButtonText(tr("Остановить"));
    // изменяем цвет кнопки на розовый
    pPlayButton->setColour(TextButton::buttonColourId, Colours::pink);
  }
  else
  {
    pPlayButton->setButtonText(tr("Играть"));
    // иначе - меняем на зелёный.
    pPlayButton->setColour(TextButton::buttonColourId, Colours::lightgreen);
  }
}
Листинг 19.4. Реализация метода changeListenerCallback класса компонента содержимого TCentralComponent (файл TCentralComponent.cpp)

Управление воспроизведением осуществляется в обработчике нажатия на кнопку pPlayButton ( пример 19.5). В нём мы используем два метода класса AudioTransportSource:

  • void AudioTransportSource::start() — начинает воспроизведение, если его источник был выбран.
  • void AudioTransportSource::stop() — останавливает воспроизведение, посылая при этом сигнал слушателю изменений (ChangeListener), зарегистрированному для текщего объекта класса AudioTransportSource.

Перед началом воспроизведения необходимо установить его позицию в текущем аудио-потоке методом void AudioTransportSource::setPosition(double newPosition). В нашем примере воспроизведение при нажатии на кнопку pPlayButton каждый раз начинается заново ( пример 19.5), однако, если сохранять текущую позицию воспроизведения, получаемую методом double AudioTransportSource::getCurrentPosition() const, в какой-либо переменной и начинать в последующем проигрывание именно с этой позиции, то можно реализовать функцию паузы. Возвращаемое методом setPosition значение представляет собой время в секундах.

else if(pButton == pPlayButton)
{
  // Если идёт воспроизведение...
  if(TransportSource.isPlaying())
  {
    // останавливаем его
    TransportSource.stop();
  }
  else
  {
    // Иначе - устанавливаем позицию в начало потока воспроизведения...
    TransportSource.setPosition(0);
    // и начинаем проигрывание файла
    TransportSource.start();
  }
}
    
Листинг 19.5. Реализация части метода buttonClicked класса компонента содержимого TCentralComponent (файл TCentralComponent.cpp)

Загрузка аудио-файла в поток, и подготовка его к воспроизведению реализована в обработчике нажатия на кнопку — pChooseButton ( пример 19.6). Выше мы уже описали взаимодействие используемых в нём классов.

void TCentralComponent::buttonClicked(Button* pButton)
{
  if(pButton == pChooseButton)
  {
    // Создаём "обёртку" для показа диалога...
    DialogWindow::showModalDialog(tr("Выбор файла"),
                pFileNameDialog,
                NULL,
                Colours::azure,
                true,
                false,
                false);
 
    // Когда файл открыт...
    CurrentFile = pFileNameDialog->getCurrentFile();
    // проверяем, существует ли он
    if(!(CurrentFile == File::nonexistent)) 
    {
      // Выводим на ярлык название файла
      pNameLabel->setText(CurrentFile.getFileName(), false);

      // Если ранее осуществлялось воспроизведение - останавливаем его.
      TransportSource.stop();
      TransportSource.setSource(0);
      pCurrentAudioFileSource = 0;
      AudioFormatManager FormatManager;
      // Загрузка файла в поток
      AudioFormatReader* pAudioFormatReader;
      // Регистрируем базовые форматы аудио
      FormatManager.registerBasicFormats();
      / Создаём чтеца для текущего аудио-файла
      pAudioFormatReader = FormatManager.createReaderFor(CurrentFile);

      if(pAudioFormatReader != 0)
      {
        // Если чтец существует, 
        // создаём с его помощью новый источник аудио-данных
        pCurrentAudioFileSource = 
        new AudioFormatReaderSource(pAudioFormatReader, true);
        // и передаём их в AudioTransportSource
        TransportSource.setSource(
            pCurrentAudioFileSource, 
            32768, 
            pAudioFormatReader->sampleRate);
        if(pCurrentAudioFileSource == 0)
        {
            AlertWindow::showMessageBox(
            AlertWindow::WarningIcon, 
            tr("Ошибка воспроизведения"), 
            tr("Отсутствует источник воспроизведения аудио-файла."), 
              tr("Принять"), 0);
          return;
        }
      }
      else AlertWindow::showMessageBox(
              AlertWindow::WarningIcon, 
              tr("Ошибка воспроизведения"), 
              tr("Не инициирован источник чтения аудио-файла.\n
              Возможно, файл повреждён."), 
              tr("Принять"), 0
              );
    }
    else
    {
      pNameLabel->setText(tr("Файл не выбран!"), false);
    }
  }
// ...
    
Листинг 19.6. Реализация части метода buttonClicked класса компонента содержимого TCentralComponent (файл TCentralComponent.cpp)

Понятно, что для того, чтобы программа, написанная с помощью Juce, могла воспроизводить тот или иной формат аудио, необходимо написать класс, унаследованный от AudioFormat, в котором будет осуществляться чтение и декодирование аудио-данных. В последующем новый аудио-формат должен быть зарегистрирован в AudioFormatManager с помощью метода void AudioFormatManager::registerFormat(AudioFormat* newFormat, bool makeThisTheDefaultFormat). В случае если мы хотим использовать новый формат по умолчанию, параметр makeThisTheDefaultFormat принимает значение true. Как упоминалось, в нашем примере мы зарегистрировали базовые аудио-форматы с помощью метода void AudioFormatManager::registerBasicFormats().

Членами сообщества уже созданы классы аудио-форматов, связывающие Juce с рядом свободных кодеков (например, avformat), что превращает её практически в универсальную мультимедийную библиотеку.

< Лекция 18 || Лекция 19: 12345 || Лекция 20 >