Информатика и образование
  Мобильная версия сайта            
               
[Главная] [Новости]
[Статьи]
[Проекты]
[Ссылки]
[Автор]
               
    [Архив новостей]        
               
  [Форум] на форуме можно задать вопрос, посмотреть ответы на часто задаваемые вопросы  
       
  Здравствуйте! Вы попали на информационно-образовательный сайт посвященный информатике, информационным технологиям и компьютерным играм. Подробнее о целях и задачах сайта в разделе Главная. [English version of this page here...]    
       
  [Базовые уроки по DirectX] [Основы DirectMusic на Delphi] [Основы DirectInput8 на Delphi] [Основы DirectSound8 на Delphi]    
  [Разработка компьютерной игры] [Пример игры Donuts3D]    
       
 

10/06/2008 Воспроизведение файлов в формате OGG Vorbis

Для воспроизведения используется интерфейс для Ogg Vorbis библиотек от Xiph.org

Автор конверсии на Delphi - Matthijs Laan, 2001 год.

   
       
 

Для создания музыки в формате ogg потребуются следующие манипуляции:

запустить Mod Plug Tracker 1.16 и открыть требуемую мелодию (*.it, *.s3m, *.xm, *.mod). Экспортировать ее в формат mp3 с требуемым качеством.

запустить Sound Forge 7.0, открыть созданный mp3-файл и пересохранить его в формате ogg с требуемым качеством.

   
       
 

Теперь рассмотрим как осуществляется процесс воспроизведения созданного файла в примере OggVorbis\demos\player

Проект Player.dpr

Модуль Main.pas

Внутри класса TMainForm

Описаны несколько приватных полей:

WaveOut: TWaveOut;
F: TFileStream;
vf: OggVorbis_File;
FileName: string;

   
       
 

При нажатии кнопки sbPlay в окне формы вызывается метод -

procedure TMainForm.sbPlayClick

Внутри него происходит следующее -

if Playing and (not Paused) then
begin
WaveOut.Pause;
//пауза
Paused := True;
Timer1.Enabled := False;
//таймер отключается
sbPlay.Glyph := Glyphs[glPlay];
end
else
if Playing and Paused then
begin
WaveOut.Unpause;
//отключение паузы
Paused := False;
Timer1.Enabled := True;
//включение таймера
sbPlay.Glyph := Glyphs[glPause];
end
else
if OpenDialog1.Execute then
PlayFile(OpenDialog1.FileName);
//загрузка ogg-файла и старт воспроизведения

   
       
  procedure TMainForm.PlayFile(FN: string);
var
res: integer;
begin
FileName := FN;

F := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); //открываем файл

res := ov_open_callbacks(F, vf, nil, 0, ops_callbacks); //передаем OggVorbis-библиотеке
if res <> 0 then
//обрабатываем ошибки открытия
begin
F.Free;
MessageDlg('ov_open_callbacks failed: ' + GetVorbisErrorName(res), mtError, [mbOK], 0);
exit;
end;

WaveOut := TWaveOut.Create(Self); //создаем поток вывода звука
WaveOut.SetWaveFormat(vf.vi.channels = 2, vf.vi.rate, 16);
//и задаем ряд параметров
WaveOut.OnStatsChange := WaveOutStatsChange;
WaveOut.OnPlayingDone := WaveOutPlayingDone;
WaveOut.ReadProc := ReadBuf;
WaveOut.OpenAudio;

GUIPlay; //отображаем воспроизведение на форме окна приложения

WaveOut.Play; //включаем фактическое воспроизведение
end;

   
       
 

//данная функция обратного вызова (callback) указанная выше

function TMainForm.ReadBuf(const Buffer; Size: Longword; var Time: Double): Longword;
var
BytesRead, Change: Longword;
begin
BytesRead := 0;

Time := ov_time_tell(vf); //считываем длительность мелодии

repeat
Change := ov_read(vf, PByteArray(Buffer)^[BytesRead], Size - BytesRead, 0, 2, 1, nil);
//загружаем данные в буфер
BytesRead := BytesRead + Change;
until (Change = 0) or (BytesRead = Size);

result := BytesRead;
end;

   
       
  При нажатии sbStop вызывается метод GUIStop -    
       
  procedure TMainForm.GUIStop;
begin
if not Playing then
//если ничего не играет, то выход
exit;

WaveOut.Free; //очищаем звуковой поток и объект OggVorbis-файла
ov_clear(vf);

Timer1.Enabled := False; //отключаем таймер
{...}

Playing := False; //сбрасываем индикатор проигрывания

{...}
end;

   
       
 

Таймер служит для отслеживания текущей позиции воспроизведения -

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
try
lTimeNow.Caption := SecondsToString(WaveOut.PlayingTime);
except
GUIStop;
raise;
end;
end;

   
       
 

Регулировка громкости -

procedure TMainForm.trackVolumeChange(Sender: TObject);
begin
if Playing then
WaveOut.Volume := DWORD(trackVolume.Position) + DWORD(trackVolume.Position) shl 16;
trackVolume.Position := WaveOut.Volume and $FFFF;
trackVolume.SliderVisible := True;
end;

procedure TMainForm.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: integer; MousePos: TPoint; var Handled: Boolean);
begin
if Playing then
if WheelDelta > 0 then
trackVolume.Position := trackVolume.Position + 3000
else
trackVolume.Position := trackVolume.Position - 3000;
Handled := True;
end;

   
       
 

При нажатии на кнопку sbNext (переход к следующей композиции списка воспроизведения) -


WaveOutPlayingDone(Self);

   
       
  procedure TMainForm.WaveOutPlayingDone(Sender: TObject);
begin
GUIStop;
//останавливаем воспроизведение

MREWSPlaylist.BeginRead; //даем сигнал чтения критической секции (для защиты от одновременных обращений к данным списка воспроизведения)
try
if Playlist.Count = 0 then
//если плей-лист пуст - выход
exit;

if Shuffle then //если включена опция выбора случайной композиции из списка, то выборка ее
begin
PlaylistForm.ListBox1.ItemIndex := Trunc(Random(Playlist.Count));
//Trunc вполне можно опустить, т.к. Random итак возвращает Integer
PlaylistForm.ListBox1DblClick(Self);
//и запуск двойного щелчка по данной композиции
exit;
end;

if (PlaylistForm.ListBox1.ItemIndex = (PlaylistForm.ListBox1.Items.Count - 1)) and Repeating then //если найдена последняя композиция списка и включена опция бесконечного повтора, то переход к первой композиции списка
begin
PlaylistForm.ListBox1.ItemIndex := 0;
PlaylistForm.ListBox1DblClick(Self);
exit;
end;

PlaylistForm.ListBox1.ItemIndex := PlaylistForm.ListBox1.ItemIndex + 1; //увеличить индекс текущего элемента на 1
PlaylistForm.ListBox1DblClick(Self);
finally
MREWSPlaylist.EndRead;
end;
end;

   
       
 

модуль Playlist.pas

procedure TPlaylistForm.ListBox1DblClick(Sender: TObject); //двойной щелчок по элементу списка воспроизведения приводит к остановке воспроизведения текущей мелодии и к старту воспроизведения выбранной
begin
MainForm.GUIStop;

MainForm.PlayFile(ListBox1.Items.Strings[ListBox1.ItemIndex]);
end;

   
       
  Теперь рассмотрим как реализовать воспроизведение различных композиций в разных состояниях приложения: запуск, показ экрана меню, настройка громкости, игровые сцены.    
       
 

Файлы необходимые для поставки с дистрибутивом игры -

vorbisfile.dll

ogg.dll

vorbis.dll

Исходные файлы - в папке OggVorbis -

AudioWaveOut.pas - вывод декодированного звука

OSTypes.pas - базовые типы

Codec.pas - интерфейс к vorbis.dll

VorbisFile.pas - интерфейс к vorbisfile.dll

Ogg.pas - интерфейс к ogg.dll

   
       
 

В опциях проекта указываем ссылку на папку OggVorbis содержащую данные файлы - Project > Options > Directories/Conditionals > Search Path

В секцию uses модуля который будет содержать команды воспроизведения добавляем ссылки на модули - AudioWaveOut, VorbisFile

   
       
  Можно также создать специальный модуль, например OggMusic.pas выполняющий роль интерфейса с данными модулями, что и было сделано - OggMusic.pas    
       
 

Правила использования:

Добавить в проект необходимые файлы - см. выше

В секции uses модуля проекта, в котором будет воспроизводиться музыка добавить ссылку на OggMusic.pas

Внутри нужного класса (приложения или игровой сцены) объявить поле с типом TOggVorbisPlayer -

В требуемых местах приложения или игровой сцены вызывать нужные методы плеера:

Например,

function TD3DGameApp.CreateSoundObjects(h_Wnd: HWND): HRESULT;
begin
//создаем OggPlayer для музыкальных тем
CreatePlayer;

{...}

function TD3DGameApp.CreatePlayer: HResult;
begin

OggMusicPlayer := TOggVorbisPlayer.Create(m_hWnd); //передаем обработчик окна приложения объекту плеера

if Assigned(OggMusicPlayer) then result := S_OK
else
result := E_FAIL;

end;

procedure TD3DGameApp.FreePlayer;
begin
FreeAndNil(OggMusicPlayer);
//удаляем плеер
end;

procedure TD3DGameApp.PlayTheme(Theme: string);
begin
if Assigned(OggMusicPlayer) then
OggMusicPlayer.Play(Theme);
//проигрываем указанный Ogg-файл
end;

procedure TD3DGameApp.StopTheme;
begin
if Assigned(OggMusicPlayer) then
//делаем паузу в воспроизведении
OggMusicPlayer.Pause;
end;


procedure TD3DGameApp.DestroySoundObjects;
begin
FreePlayer;
//вызываем удаление плеера

   
       
 

Доработки: поскольку музыка играет без использования IDirectSound, то при сворачивании окна приложения она продолжает играть. Чтобы это исправить можно вызывать метод паузы на время пока приложение неактивно.

Ряд вопросов:

насколько велика временная задержка при переключении на проигрывание новой мелодии?

насколько велика задержка при бесконечном воспроизведении? Она должна быть равна вышеуказанной, т.к. проигрывание той же мелодии происходит путем очистки объекта WaveOut с последующей повторной загрузкой.

   
       
  Регулировка громкости музыки из окна Настройки - см. следующую статью    
       
  [Назад] [Все уроки]    
       
 

Обновления и новости о развитии Delphi DirectX проекта
смотри на сайтах:

http://www.megainformaticsite.pochta.ru

http://www.megainformatic.boom.ru

http://www.megainformatic.narod.ru

 

   
       
 

Cвои пожелания, вопросы или заметки отправляйте на:

megainformatic@mail.ru

 
     
   Обмен ссылками  
     
     
             
 
 
         
(с) МЕГА ИНФОРМАТИК 2006-2009
Hosted by uCoz