В данной статье рассматривается функция 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 – может принимать одно из следующих значений:
- Test – служит для определения возможности выполнения команды, при этом сама команда устройству не отправляется.
- Wait – при этом флаге управление программе передаётся только после выполнения команды.
- 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
Классно!
Здравствуйте. Спасибо большое. Пишу только-только взглянув на статью(точнее скопировав себе для дальнейшего ознакомления =) ), но даже на первый взгляд очень информативная и удобочитаемая! (тем более, если Алексей Николаевич Родионов пишет, что «Классно!», то мне точно понравится)))) Я как раз пишу курсовую работу по обработке звука.Спасибо большое.
Огромное спасибо! Уже неделю рою интернет в поисках способа восапрозведения видео без использования TMedaiPlayer (ужасно бедный компонент, просто бесит!)… DirectX тоже не хотелось использовать (пока). Далее нашёл общее описание по mciSendString, но было не понятно без примеров: http://msdn.microsoft.com/en-us/library/windows/desktop/dd757161%28v=VS.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/dd743572%28v=VS.85%29.aspx ..а тут Ваша статья с очень хорошими примерами использования данной функций!! Ещё раз спасибо! Дальше сам
Замечательная команда и пример шикарный. Может кто-нибудь еще подскажет можно ли поменять громкость воспроизводимого звука. Сам я что-то не нашел..
Выдает ошибку устройство MCI не найдено при воспроизведении wav файла Можно как-нибудь это исправить?