Сейчас на форуме: (+5 невидимых)

 eXeL@B —› Программирование —› Как проиграть midi из ресурса
Посл.ответ Сообщение

Ранг: 20.5 (новичок)
Активность: 0.020
Статус: Участник

Создано: 09 июля 2007 11:25
· Личное сообщение · #1

Уважаемые посетители форума!
Я давно уже хотел узнать, как проиграть midi-файл из ресурса. Естественно, напрямую, без всяких трюков с сохранением на диск, воспроизведением через mciSendCommand и последующим стиранием. Недавно нашёл кое-какую информацию по этой теме, попробовал реализовать (на Delphi), но постоянно происходит одна и та же ошибка. Может кто-нибудь знает, как пользоваться этими API и посмотрит, в чём дело:

uses MMSYSTEM;

...

var
hRes : DWORD; // Это для
pRes : Pointer; // ресурсов

midi : HMIDI; //Handle потока воспроизведения
header : MIDIHDR; //Заголовок с информацией для потока
pDev : integer; //Номер устройства воспроизведения

err : DWORD; //Код ошибки
begin
//Файл 1.mid полностью загнан в ресурс '1' типа 'MIDI'
//Все функции, кроме последней (midiStreamOut),
//выполняются без ошибок

//Загружаем ресурс
hRes:=FindResource(hInstance,PChar(1),PChar('MIDI'));
hRes:=LoadResource(hInstance,hRes);
pRes:=LockResource(hRes);
//Инициализация параметров
pDev:=MIDI_MAPPER; midi:=0;
FillChar(header,SizeOf(header),0);
//Создание потока и подготовка заголовка
midiStreamOpen(@midi,@pDev,1,0,0,0);
header.lpData:=pRes;
header.dwBufferLength:=4373;
header.dwFlags:=0;
midiOutPrepareHeader(midi,@header,SizeOf(header));
//Попытка проиграть...
err:=midiStreamOut(midi,@header,SizeOf(header));
showmessage(inttostr(err))
//err=11 (equ 'Неверные параметры'), а должен быть 0
end;



Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 09 июля 2007 14:55
· Личное сообщение · #2

А может так сделать:

header.dwBufferLength:=SizeofResource(hInstance,hRes);




Ранг: 20.5 (новичок)
Активность: 0.020
Статус: Участник

Создано: 09 июля 2007 16:28
· Личное сообщение · #3

Неа не идёт Та же ошибка



Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 09 июля 2007 18:10
· Личное сообщение · #4

у меня ошибка уже не та же. была 11 как у тебя, а стала 64. просто не учел особенностей твоего кода =)

hRes:=FindResource(hInstance,PChar(1),PChar('MIDI'));
dwSize := SizeofResource(hInstance,hRes);
hRes:=LoadResource(hInstance,hRes);
...
header.dwBufferLength:=dwSize;
header.dwBytesRecorded:=dwSize;

и теперь еще midiOutPrepareHeader возвращает 11. =(((
не знаю, шаг назад я сделал или вперед :/



Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 09 июля 2007 18:18
· Личное сообщение · #5

дебажил winmm.dll внутри midiOutPrepareHeader и нашёл следующее:

76B36CF8 CMP DWORD PTR DS:[ESI+4],10000
76B36CFF JBE SHORT winmm.76B36D09
76B36D01 PUSH 0B
76B36D03 POP ESI
76B36D04 JMP winmm.76B36E0D
...
76B36E0D PUSH DWORD PTR SS:[EBP-8]
76B36E10 CALL DWORD PTR DS:[<&KERNEL32.LeaveCriticalSection>]
76B36E16 MOV EAX,ESI
76B36E18 JMP SHORT winmm.76B36E4A
...
76B36E4A POP EDI
76B36E4B POP EBX
76B36E4C POP ESI
76B36E4D LEAVE
76B36E4E RETN 0C

0x0B - код ошибки MMSYSERR_INVALPARAM.
[ESI+4] - это значение поля dwBufferLength. у меня midi-файл на 100 кб, точный размер - 0x18C3F, а это больше, чем 0x10000. с таким длинным буфером не работает =(( и что же делать?



Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 09 июля 2007 18:36
· Личное сообщение · #6

И еще я решил, что нельзя передавать содержимое .mid-файла в качестве stream. stream это нечто другое.
вот к примеру, я добился:

var
...
test : array [0..5] of ulong;
...
begin
...
test[0] := 0;
test[1] := 0;
test[2] := $7F3C90;
test[3] := 192;
test[4] := 0;
test[5] := $3C90;
dwSize := sizeof(test);
header.lpData:=@test;
header.dwBufferLength:=dwSize;
header.dwBytesRecorded := dwSize;

играет одну ноту =)))



Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 09 июля 2007 18:41
· Личное сообщение · #7

еще могу посоветовать сохранить файл в temp-папку и играть из файла через mciSendCommand(..,MCI_PLAY).
при выходе просто удалить =)



Ранг: 20.5 (новичок)
Активность: 0.020
Статус: Участник

Создано: 10 июля 2007 10:52
· Личное сообщение · #8

Большое спасибо за информацию! Из неё можно сделать вывод, что midiStreamOpen - это
действительно нечто другое. Дело в том, что недавно на каком-то форуме, где обсуждалась
подобная проблема, кто-то написал, что долго мучился и справился в конце концов с помощью
функций midiStreamOpen, midiStreamOut и т д. И вот нет чтобы написать кусок кода, так ведь
нет же, просто написал названия функций и ушёл. Возможно, что ничего у него не получилось, а
он просто увидел "умные" названия API и написал. Не исключено также, что он был совсем уж
маньяк =) и "на лету" перебивал midi-файл в правильную для Stream'а структуру. Так что тут
многое непонятно.
PS. А буфер не должен превышать 64 кб, это в справке по функции сказано.
PPS.А ещё есть функции midiOutOpen, midiOutClose, midiOutShortMsg, midiOutLongMsg и др.
(вообще много информации по всем этим функциям на promidi.by.ru/)



Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 10 июля 2007 13:18
· Личное сообщение · #9

как разделаюсь с другими своими делами, буду реверсить обработчик MCI_PLAY - может там не так всё и страшно...



Ранг: 203.3 (наставник)
Активность: 0.220
Статус: Участник
UPX Killer -d

Создано: 10 июля 2007 15:13
· Личное сообщение · #10

sotona пишет:
И еще я решил, что нельзя передавать содержимое .mid-файла в качестве stream. stream это нечто другое.
вот к примеру, я добился:

Вы имеете ввиду стрим == midiStreamOpen(@midi,@pDev,1,0,0,0);
А ежели как в вашем примере с набором байт, но подгрузить миди-файл в TStream (TMemoryStream) ?

-----
Я медленно снимаю с неё UPX... *FF_User*




Ранг: 51.0 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 10 июля 2007 16:35
· Личное сообщение · #11

AlexZ пишет:
А ежели как в вашем примере с набором байт, но подгрузить миди-файл в TStream (TMemoryStream) ?

у mid-файла свой формат. сначала сигнатура 'MT', потом заголовок. и в файле таких stream'ов должно быть несколько. вот как их оттуда взять и пустить параллельно - это вопрос.



Ранг: 203.3 (наставник)
Активность: 0.220
Статус: Участник
UPX Killer -d

Создано: 10 июля 2007 18:04 · Поправил: AlexZ
· Личное сообщение · #12

Да-да... сейчас поигрался с TStream и выяснил, что придется разбирать на дорожки.
Ранее вопрос воспроизведения мидях из памяти уже неоднократно поднимался, и скажу, что было решено играть его из файла с диска. Хотя, если память не подводит, товарисчь Asterix что-то эксперементировал с API PlaySound и флагом "из_памяти", но кажись, тоже окончилось неудачей.

P.s. Есть тулзень GuitarPro для сочинения мидях, может её стОит реверснуть...

-----
Я медленно снимаю с неё UPX... *FF_User*





Ранг: 61.7 (постоянный)
Активность: 0.050
Статус: Участник
я

Создано: 10 июля 2007 19:06
· Личное сообщение · #13

Да, эта проблема для меня тоже очень важна. В аттаче есть мой давний пример на фасме как играть миди-поток. Там используется два инструмента (Kick и еще что-то), миди-буфер построен вручную(чем то сродни писать музыку в MadTracker . В архиве так же есть доки по миди-формату.
Как выход из ситуации могу предложить написать тулзу которая будет "обычный" мидик переводить в такой вот миди-поток без заголовков и его уже и играть... Скорее всего миди-плееры считывают из файла все дорожки, потом "склеивают" их в один поток, бьют на блоки по 64К и играют уже данными API.

P.S.: мб я и неправ насчет всего этого




Ранг: 61.7 (постоянный)
Активность: 0.050
Статус: Участник
я

Создано: 10 июля 2007 19:07
· Личное сообщение · #14

Прикольно, аттач то забыл

7d3c_10.07.2007_CRACKLAB.rU.tgz - MIDI.zip


 eXeL@B —› Программирование —› Как проиграть midi из ресурса
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати