Программирование на Delphi и не только » Архив блога Мультимедиа под контролем или Функция mciSendString | Программирование на Delphi и не только

    В данной статье рассматривается функция mciSendString, которая находится в библиотеке winmm.dll. Эта функция может подавать команды любому MCI (Media Control Interface) устройству (поддерживаемое системой мультимедиа устройство: WAV, MIDI, CDAudio, Video и т.п.). Вот её синтаксис:

MCIERROR mciSendString(   LPCTSTR lpszCommand,   LPTSTR lpszReturnString,   UINT cchReturn,   HANDLE hwndCallback

);

lpszCommand – команда; lpszReturnString – строка результата; cchReturn – размер в символах строки результата; hwndCallback – окно отзыва (используется только при установленном в первом параметре флага «notify»).     Все дальнейшие примеры будут написаны на Delphi, но их перевод на другие языки, я думаю, не составит особого труда.

    Теперь условимся с параметрами функция mciSendString в последующих примерах:

  • HwndCallback: будет принимать значение 0;

  • CchReturn: будет принимать значение 64 (в MSDN написано, что это максимальная длина ошибки, которая может быть возвращена параметром lpszReturnString);

  • LpszReturnString: в этом параметре будем использовать переменную sbReturn: array [1..64] of char;

    Пришло время перейти к самому главному параметру функции – lpszCommand. Эта команда составляется при помощи специальных операторов, часть которых рассматривается далее.

Open Эта команда поддерживается всеми устройствами. Она служит для инициализации устройства. Синтаксис команды:

‘open lpszDeviceID lpszOpenFlags lpszFlags’

Параметры:

LpszDeviceID – идентификатор одного из устройств (или его псевдоним), прописанных в разделе [MCI] файла System.ini или в реестре. Может указывать также на драйвер. Например: cdaudio, sequencer, waveaudio, MyDriver.drv.

LpszOpenFlags – флаг, определяющий дополнительные параметры инициализации устройства. Я не буду приводить весь список значений этого параметра для каждого устройства, а упомяну лишь значение «alias device_alias type device_type», которое открывает устройство типа device_type под псевдонимом device_alias.
LpszFlags – может принимать одно из следующих значений:

  1. Test – служит для определения возможности выполнения команды, при этом сама команда устройству не отправляется.
  2. Wait – при этом флаге управление программе передаётся только после выполнения команды.
  3. Notify – при этом флаге программа получит специальное сообщение, при помощи которого сможет узнать о завершении выполнения команды, а управление передаётся без промедления.

Пример:
mciSendString(‘open d:\Sound.wav type waveaudio alias MyWave wait’, nil, 0, 0); — связывает устройство WaveAudio под псевдонимом MyWave с файлом d:\Sound.wav.

Play Эта команда запускает проигрывание для одного из следующих устройств: CD audio, digital-video, MIDI sequencer, videodisc, VCR, и waveform-audio. Синтаксис команды:

‘play lpszDeviceID lpszPlayFlags lpszFlags’

Параметры:

  • LpszDeviceID – идентификатор одного из устройств (или его псевдоним), прописанных в разделе [MCI] файла System.ini. Например: cdaudio, sequencer, waveaudio, avivideo.
  • LpszPlayFlags – флаг, определяющий тип проигрывания устройства. В Таблице 1 приведён список значений этого параметра для каждого устройства, а в Таблице 2 даны пояснения для этих значений.

Пример:
mciSendString(‘play cdaudio’, nil, 0, 0); — музыкальный компакт-диск начинает проигрываться либо с начала, либо с позиции, зафиксированной командой «Пауза».

Status
Данная команда служит для определения различных параметров. Параметров много, поэтому все их приводить не буду. Остановлюсь лишь на командах для музыкальных компакт-дисков.

  • cdaudio type track number – для определения типа дорожки с номером number
  • current track – для определения номера текущей композиции length – для определения длины диска length track number – для определения длины композиции с номером number media present – для определения наличия диска в CD-ROM mode – для определения состояния проигрывания: playing, stopped, paused, open, not ready, parked, recording или seeking.
  • number of tracks – для определения количества дорожек на диске position – для определения текущей позиции диска position track number – для определения начальной позиции дорожки с номером number ready – возвращает истину, если устройство может принимать другие команды start position – начальная позиция диска
  • time format – формат времени, используемый в данной сессии работы с устройством.

    На этом закончим с теорией и перейдём к практике. Напишем при помощи функции mciSendString проигрыватель музыкальных компакт-дисков. Конечно, мы рассмотрели не все команды, которые нам понадобятся, но, я думаю, что проблем не возникнет, т.к. остальные команды достаточно просты в употреблении.
Создайте в Delphi новый проект и приведите форму к нужному виду (см. рис.1).

Для этого понадобятся следующие компоненты: TLabel (5 штук), TButton (7 штук), TListBox, TTrackBar и TTimer. К списку модулей добавьте MMSystem. Теперь объявите две глобальные переменные:
var
  sbReturn: array [1..64] of char; //для возвращаемых значений
  com: pchar; //посылаемая команда

После этого можно писать функции для управления проигрыванием: //переход к дорожке с номером Track

procedure gototrack(Track: integer);

var   com:pchar;

begin

  //установка формата времени в «Дорожка:Минуты:Секунды:Фреймы»   com:=’set cdaudio time format tmsf’;   mciSendString(com, @sbReturn, 64, 0);   //начинаем проигрывание дорожки Track   com:=pchar(‘play cdaudio from ‘+inttostr(Track));   mciSendString(com, @sbReturn, 64, 0);   //устанавливаем формат времени в миллисекунды   com:=’set cdaudio time format ms’;   mciSendString(com, @sbReturn, 64, 0);

end;

//получение номера текущей композиции
function GetCurrentTrack:byte;
var   com:pchar;   st:string;

begin

  result := 0;   com := ‘status cdaudio current track wait’;

  if (mciSendString(com, @sbReturn, 64, 0) 0) then

    exit;   st := trim(sbReturn);

  if (length(st) > 0) then

    result := strtoint(st);

end;

//количество композиций на диске
function GetTracksCnt: integer;
var   st:string;

begin

  result := 0;   com := ‘status cdaudio number of tracks wait’;

  if (mciSendString(com, @sbReturn, 64, 0) 0) then

    exit;   st := trim(sbreturn);

  if (length(st) > 0) then

    result := strtoint(st);

end;

//переход к следующей композиции
procedure NextTrack;
var   cur:integer;

begin

  cur:=GetCurrentTrack;   //если текущая композиция – последняя, то переходим к первой

  if (cur then

    GoToTrack(cur+1)

  else

    GoToTrack(1);

end;

//переход к предыдущей композиции
procedure PrevTrack;
var   cur:integer;

begin

  cur := getcurrentTrack;

  if (cur > 1) then

    GoToTrack(cur-1)   //если текущая композиция – первая, то переходим к последней  

  else

    GoToTrack(GetTracksCnt);

end;

//длина композиции
function GetTrackLength(Track: integer): string;
begin   com := pchar(‘status cdaudio length track ‘+inttostr(Track)+’ wait’);   mciSendString(com, @sbReturn, 64, 0);   result := trim(sbReturn);

end;

//длина диска
function GetCDLength:string;
begin   com := pchar(‘status cdaudio length wait’);   mciSendString(com, @sbReturn, 64, 0);   result := trim(sbReturn);

end;

//статус проигрывания
function GetStatus:string;
begin   com := ‘status cdaudio mode wait’;   mciSendString(com, @sbReturn, 64, 0);   result := trim(sbReturn);

end;

//есть ли диск
function IsCDReady:string;
begin   com := ‘status cdaudio ready wait’;   mciSendString(com, @sbReturn, 64, 0);   result := trim(sbReturn);

end;

//Начать проигрывание
procedure PlayCD;
begin   mciSendString(‘play cdaudio’, @sbReturn, 64, 0);

end;

//Пауза
procedure PauseCD;
begin   mciSendString(‘pause cdaudio wait’, @sbReturn, 64, 0);

end;

//Остановить проигрывание
procedure StopCD;
begin   mciSendString(‘stop cdaudio wait’, @sbReturn, 64, 0);

end;

//начальная позиция композиции
function GetTrackPos(Track:word): string;
begin   com := pchar(‘status cdaudio position track ‘+inttostr(Track)+’ wait’);   mciSendString(com, @sbReturn, 64, 0);   result := trim(sbReturn);

end;

//текущая позиция диска
function GetCDPos: string;
begin   com := pchar(‘status cdaudio position wait’);   mciSendString(com, @sbReturn, 64, 0);   result := trim(sbReturn);

end;

А теперь напишем обработчики различных событий для компонентов: //инициализируем устройство при загрузке

procedure TForm1.FormCreate(Sender: TObject);

begin   mciSendString(‘open cdaudio’, @sbReturn, 64, 0);

end;

//при выходе закрываем устройство
procedure TForm1.FormDestroy(Sender: TObject);
begin   mciSendString(‘close cdaudio wait’, @sbReturn, 64, 0);

end;

{при появлении формы записываем в ListBox список композиций}

procedure TForm1.FormShow(Sender: TObject);

var   i: word;

begin

  for i := 1 to GetTracksCnt do
  begin     Listbox1.Items.Add(inttostr(i)+’ ‘+GetTrackLength(i));

  end;
end
;

//кнопка Play
procedure TForm1.Button1Click(Sender: TObject);
begin   PlayCD;

end;

//кнопка Pause
procedure TForm1.Button2Click(Sender: TObject);
begin   PauseCD;

end;

//кнопка Stop
procedure TForm1.Button3Click(Sender: TObject);
begin   StopCD;

end;

//кнопка Next (следующая композиция)
procedure TForm1.Button4Click(Sender: TObject);
begin   NextTrack;

end;

//кнопка Prev (переход к предыдущей композиции)
procedure TForm1.Button5Click(Sender: TObject);
begin   PrevTrack;

end;

//процедура для таймера, повторяющаяся каждую секунду
procedure TForm1.Timer1Timer(Sender: TObject);
var   cur, i: word;   st: string;   cnt: byte;   hour: word;   min, sec: byte;   t: integer;

begin

  //выводим состояние проигрывания   label5.Caption:=’Состояние: ‘+GetStatus;

  if (GetStatus ‘playing’) and

      (GetStatus’stopped’) and
      (GetStatus’paused’) then exit;   //устанавливаем формат времени в миллисекунды   com:=’set cdaudio time format ms wait’;   mciSendString(com, @sbReturn, 64, 0);   cur:=GetCurrentTrack;   //выделяем в списке композиций текущую   ListBox1.ItemIndex:=cur-1;   {выводим формат времени, эти строки только для примера, т.к. мы сами недавно   установили формат в миллисекунды}   com:=’status cdaudio time format wait’;   mciSendString(com, @sbReturn, 64, 0);   //выводим информацию информацию   label2.Caption:=’Формат времени: ‘+trim(sbReturn);   label3.Caption:=’Начальная позиция: ‘+GetTrackPos(cur);   label4.Caption:=’Текущая позиция: ‘+GetCDPos;   {устанавливаем ползунок TrackBar’a в нужную позицию, соответствующую текущему   положению проигрываемой композиции}   TrackBar1.Max:=strtoint(GetTrackLength(cur)) div 1000;   t:=strtoint(GetCDPos)-strtoint(GetTrackPos(cur));

  t:=t div 1000;

  TrackBar1.Position:=t;

  hour:=t div 3600;

  t:=t mod 3600;
  min:=t div 60;
  t:=t mod 60;   sec:=t;   st:=format(‘%d:%d’,[min,sec]);

  if (hour > 0) then

  st:=inttostr(hour)+’:’+st;   //выводим время проигрывания текущей композиции   label1.Caption:=st;

end;

//при двойном щелчке по композиции из списка начинаем её проигрывание
procedure TForm1.ListBox1DblClick(Sender: TObject);
begin   GoToTrack(ListBox1.ItemIndex+1);

end;

//перемотка композиции на 5 секунд вперёд
procedure TForm1.Button6Click(Sender: TObject);
var   t: integer;

begin

  t := strtoint(GetCDPos)+5000;   StopCD;   com := pchar(‘seek cdaudio to ‘+inttostr(t)+’ wait’);   mciSendString(com, @sbReturn, 64, 0);   PlayCD;

end;

//перемотка композиции на 5 секунд назад
procedure TForm1.Button7Click(Sender: TObject);
var   t: integer;

begin

  t := strtoint(GetCDPos)-5000;   StopCD;   com := pchar(‘seek cdaudio to ‘+inttostr(t)+’ wait’);   mciSendString(com, @sbReturn, 64, 0);   PlayCD;

end;

    Вот и готов CD-проигрыватель, написанный на достаточно низком уровне при помощи, в принципе, всего одной функции, вынесенной в заглавие статьи. Вот такая вот функция! А ведь она может не только с музыкальным компакт-диском управляться: не следует забывать и про видеодиски, устройства записи и проигрывания мультимедиа и т.п.
Конечно, в CD-проигрывателе почти отсутствует контроль ошибок, и некоторые участки кода можно оптимизировать, но свою функцию эта программа в данной статье выполняет: демонстрирует применение функции mciSendString для различных задач.

Иван Ширко
ishyrko@gmail.com