Хочу спросить а в новые компы и операциоки встраивают микросхему синтезатора или программно драйвер?
Или сейчас через библиотеки другие?
Миди синтезатор
Сообщений 1 страница 30 из 36
Поделиться128.07.2021 01:30:40
Поделиться228.07.2021 03:23:30
Sergeihik
теоретически зачем? Примитивное проигрывание midi и так работает, и даже не такое уж примитивное, взависимости от драйвера и программы. Ну а качественное с железной реализацией, для этого наверно существуют специальные аудиокарты и скорее всего внешнее устройство. Зачем в комп пихать то что не будет использоваться на 99%.
Вот пример
Поделиться328.07.2021 07:06:51
Обращение к midi реализовано через API
dwDuration.l=550
hMidiOut.l
;--------------------------------------------------
rc.l=midiOutOpen_(@hMidiOut,#MIDI_MAPPER,#Null,0,#CALLBACK_NULL)
If rc=#MMSYSERR_NOERROR
Restore lpNoteList
For i=0 To 15
Read.l a.l
midiOutShortMsg_(hMidiOut,a)
b.l=a
If a&$F0=$90
b&$FFFF0F
b!128
Sleep_(dwDuration)
midiOutShortMsg_(hMidiOut,b)
EndIf
Next i
midiOutClose_(hMidiOut)
Else
Debug "err:"+Str(rc)
EndIf
DataSection
lpNoteList:
Data.l $75C0
Data.l $7f3090 ;two octave scale C to C
Data.l $7f3290
Data.l $7f3490
Data.l $7f3590
Data.l $7f3790
Data.l $7f3990
Data.l $7f3b90
Data.l $7f3c90
Data.l $7f3e90
Data.l $7f4090
Data.l $7f4190
Data.l $7f4390
Data.l $7f4590
Data.l $7f4790
Data.l $7f4890
Data.l 0 ;terminate list with a 0
Поделиться430.07.2021 02:52:32
Sergeihik
теоретически зачем? Примитивное проигрывание midi и так работает, и даже не такое уж примитивное, взависимости от драйвера и программы. Ну а качественное с железной реализацией, для этого наверно существуют специальные аудиокарты и скорее всего внешнее устройство. Зачем в комп пихать то что не будет использоваться на 99%.
Вот пример
Да так балуюсь хочу что то наподобие этого сделать https://www.youtube.com/watch?v=bTO6I6RJL_Y
Structure hMidiOut;тупо для ссылки на процедуры
hMidiOut.i
EndStructure
;
Structure notaON
konalkomanda.a
nomernotON.a
silaudara.a
huiznatstarhyibait.a
EndStructure
Structure notaOF
konalkomanda.a
nomernotyOf.a
zatuhanie.a
huiznatstarhyibait.a
EndStructure
Structure nota
StructureUnion
notaON.notaON
komandanotyON.i
EndStructureUnion
;
StructureUnion
notaOF.notaOF
komandanotyOF.i
EndStructureUnion
time_uderganiy_klavihi.i
time_pause.i
EndStructure
Global Klaviha.nota
Klaviha\notaON\konalkomanda=$90
Klaviha\notaON\silaudara=127
Klaviha\notaOF\konalkomanda=$80
Klaviha\notaOF\zatuhanie=127
#Channel1 = 0
Global hMidiOut.i
Global midiport.i
Procedure Error(funkciy$,ohibka.i)
Select ohibka
Case #MIXERR_BASE
MessageRequester(funkciy$,"Минимальное значение кода ошибки микшера")
Case #MIXERR_INVALLINE
MessageRequester(funkciy$,"Недопустимый индекс/идентификатор линии")
Case #MIXERR_INVALCONTROL
MessageRequester(funkciy$,"Недопустимый индекс/идентификатор элемента управления")
Case #MIXERR_INVALVALUE
MessageRequester(funkciy$,"Недопустимое значение элемента управления")
Case #MIXERR_LASTERROR
MessageRequester(funkciy$,"Максимальное значение кода ошибки микшера")
Case #MMSYSERR_ALLOCATED
MessageRequester(funkciy$,"Устройство занято другим приложением")
Case #MMSYSERR_BADDEVICEID
MessageRequester(funkciy$,"Недопустимый номер устройства")
Case #MMSYSERR_NOTENABLED
MessageRequester(funkciy$,"Драйвер не активизирован")
Case #MMSYSERR_INVALFLAG
MessageRequester(funkciy$,"Один или несколько флагов недействительны.")
Case #MMSYSERR_INVALHANDLE
MessageRequester(funkciy$,"Недопустимый дискриптор открытого устройства")
Case #MMSYSERR_INVALPARAM
MessageRequester(funkciy$,"Один или несколько параметров недействительны.")
Case #MMSYSERR_NODRIVER
MessageRequester(funkciy$,"Драйвер отсутствует")
Case #MMSYSERR_NOMEM
MessageRequester(funkciy$,"Недостаточно памяти для выделения")
Case #MMSYSERR_NOTSUPPORTED
MessageRequester(funkciy$,"Запрошенная функция не поддерживается")
Case #MMSYSERR_HANDLEBUSY
MessageRequester(funkciy$,"Над ключом выполняется операция от другой задачи (thread)")
Case #MMSYSERR_INVALIDALIAS ;13
Case 14;#MMSYSERR_BADDB ;14
Case 15;#MMSYSERR_KEYNOTFOUND ;15
Case 16;#MMSYSERR_READERROR ;16
Case 17;#MMSYSERR_WRITEERROR; 17
Case 18;#MMSYSERR_DELETEERROR ;18
Case 19;#MMSYSERR_VALNOTFOUND ;19
Case 20;#MMSYSERR_NODRIVERCB
;MessageRequester(funkciy$,"Драйвер не выполнил уведомления (callback)")
Case #MMSYSERR_BADERRNUM
MessageRequester(funkciy$,"Код ошибки вне допустимого диапазона")
Case #MMSYSERR_ERROR
MessageRequester(funkciy$,"Неопределенная ошибка")
EndSelect
EndProcedure
Procedure.i midiinit(Konstanta.i)
Protected midi.MIDIOUTCAPS
Protected devnum
#MOD_MIDIPORT =1;Аппаратный порт MIDI.
#MOD_SYNTH =2;Синтезатор
#MOD_SQSYNTH=3;Синтезатор прямоугольных импульсов.
#MOD_FMSYNTH=4;FM-синтезатор.
#MOD_MAPPER =5;Microsoft MIDI маппер.
#MOD_WAVETABLE=6;Аппаратный волновой синтезатор.
#MOD_SWSYNTH=7 ;Программный синтезатор
If midiOutGetNumDevs_();извлекает количество MIDI-устройств вывода,0=нет устройств
For devnum=0 To 7
If midiOutGetDevCaps_(devnum,@midi,SizeOf(MIDIOUTCAPS))=0
Debug midi\wTechnology;что есть
If midi\wTechnology=Konstanta;#MOD_SWSYNTH
Debug PeekS(@midi\szPname,-1,#PB_Unicode);Название продукта в строке с нулевым символом в конце.
Debug midi\wVoices;количество голосов
Debug midi\wNotes ;количество одновременных нот, которые могут быть воспроизведены
Debug midi\wChannelMask;Портовые устройства, которые передают по всем каналам, устанавливают этот элемент в 0xFFFF.
Debug midi\dwSupport;Дополнительный функционал, поддерживаемый устройством(MIDICAPS_VOLUME=1 Поддерживает регулировку громкости.)
ProcedureReturn devnum
EndIf
EndIf
Next
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i midiOutOpen(midiport.i,*hMidiOut.hMidiOut,flagi.i,dwCallback.i=0,CallbackInstance.i=0);открывает выходное MIDI-устройство
Protected result.i
result=midiOutOpen_(*hMidiOut.hMidiOut,midiport,dwCallback,CallbackInstance,flagi)
If result=MMSYSERR_NOERROR
ProcedureReturn 1
Else
Error("Error midiOutOpen()",result)
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i midiOutClose(*hMidiOut);получаем дискриптор устройства
Protected MidiOut.i
!mov dword eax,[p.p_hMidiOut]
!mov dword eax,[eax]
!mov dword [p.v_MidiOut],eax
If midiOutClose_(MidiOut)=#MMSYSERR_NOERROR
!mov dword eax,[p.p_hMidiOut]
!mov dword [eax],0
ProcedureReturn 1
Else
MessageRequester("Error midiOutClose()","INVALIDE_HANDLE hMidiOut")
ProcedureReturn 0
EndIf
EndProcedure
Procedure MidiOutMessage(hMidi,iStatus,iChannel,iData1,iData2)
dwMessage = iStatus | iChannel | (iData1 << 8 ) | (iData2 << 16)
ProcedureReturn midiOutShortMsg_(hMidi, dwMessage) ;
EndProcedure
Procedure SetInstrument(channel,instrument)
MidiOutMessage(hMidiOut, $C0, channel, instrument, 0)
EndProcedure
Procedure pleysound()
;Klaviha\notaON\nomernotON=30
;Klaviha\notaOF\nomernotyOf=30
For i=0 To 127
Klaviha\notaON\nomernotON=Random(127)
Klaviha\notaOF\nomernotyOf=Random(127)
Klaviha\time_uderganiy_klavihi=Random(150)
Klaviha\time_pause=Random(150)
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON);нота on
; Delay(50)
Delay(Klaviha\time_uderganiy_klavihi)
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyOF);нота of
Delay(Klaviha\time_pause)
Next
EndProcedure
Procedure _Beep(nota,octave=2,Duration=200,pause=0)
nota=nota+0+12*octave
Klaviha\notaON\nomernotON=nota
Klaviha\notaOF\nomernotyOf=nota
Klaviha\time_uderganiy_klavihi=Duration
Klaviha\time_pause=pause
;;Polyphonic Mode On ,проигрывает ноты в канале одновременно
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON);нота on
Klaviha\notaON\nomernotON=nota-30
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota+50
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota+100
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota+80
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota+23
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota+45
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota-24
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Klaviha\notaON\nomernotON=nota-24
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyON)
Delay(Klaviha\time_uderganiy_klavihi)
midiOutShortMsg_(hMidiOut, Klaviha\komandanotyOF);нота of
MidiOutMessage(hMidiOut,$B0, 0, $7B, 0);All Notes Off
;MidiOutMessage(hMidiOut,$B0, 0, 120, 0);All Sounds Off
Delay(Klaviha\time_pause)
EndProcedure
Procedure pleysound2()
_Beep(1,6,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(1,6,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(9,5,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(1,5,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(9,5,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(1,5,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(12,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(12,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(1,6,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(1,6,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,6,100)
_Beep(9,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(4,5,100)
_Beep(9,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(4,6,100)
_Beep(9,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(4,5,100)
_Beep(9,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(3,6,100)
_Beep(7,5,100)
_Beep(5,5,100)
_Beep(7,5,100)
_Beep(3,5,100)
_Beep(7,5,100)
_Beep(5,5,100)
_Beep(7,5,100)
_Beep(3,6,100)
_Beep(7,5,100)
_Beep(5,5,100)
_Beep(7,5,100)
_Beep(3,5,100)
_Beep(7,5,100)
_Beep(5,5,100)
_Beep(7,5,100)
_Beep(3,6,100)
_Beep(8,5,100)
_Beep(7,5,100)
_Beep(8,5,100)
_Beep(3,5,100)
_Beep(8,5,100)
_Beep(7,5,100)
_Beep(8,5,100)
_Beep(3,6,100)
_Beep(8,5,100)
_Beep(7,5,100)
_Beep(8,5,100)
_Beep(3,5,100)
_Beep(8,5,100)
_Beep(7,5,100)
_Beep(8,5,100)
_Beep(1,6,100)
_Beep(5,5,100)
_Beep(3,5,100)
_Beep(5,5,100)
_Beep(1,5,100)
_Beep(5,5,100)
_Beep(3,5,100)
_Beep(5,5,100)
_Beep(1,6,100)
_Beep(5,5,100)
_Beep(3,5,100)
_Beep(5,5,100)
_Beep(1,5,100)
_Beep(5,5,100)
_Beep(3,5,100)
_Beep(5,5,100)
_Beep(1,6,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(1,5,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(1,6,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(1,5,100)
_Beep(6,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(11,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(11,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(11,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(11,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(8,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(11,4,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(9,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(11,4,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(8,5,100)
_Beep(11,4,100)
_Beep(9,4,100)
_Beep(11,4,100)
_Beep(4,5,100)
_Beep(11,4,100)
_Beep(9,4,100)
_Beep(11,4,100)
_Beep(8,5,100)
_Beep(11,4,100)
_Beep(9,4,100)
_Beep(11,4,100)
_Beep(4,5,100)
_Beep(11,4,100)
_Beep(9,4,100)
_Beep(11,4,100)
_Beep(6,5,100)
_Beep(1,5,100)
_Beep(11,4,100)
_Beep(1,5,100)
_Beep(10,4,100)
_Beep(1,5,100)
_Beep(11,4,100)
_Beep(1,5,100)
_Beep(6,5,100)
_Beep(1,5,100)
_Beep(11,4,100)
_Beep(1,5,100)
_Beep(10,4,100)
_Beep(1,5,100)
_Beep(11,4,100)
_Beep(1,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(12,4,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(12,4,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(12,4,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(12,4,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(6,4,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(6,4,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(7,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(7,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(7,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(10,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(7,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(10,4,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(9,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(9,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,3,1600)
;=========================
_Beep(8,3,100)
_Beep(12,3,100)
_Beep(3,4,100)
_Beep(6,4,100)
_Beep(9,4,100)
_Beep(6,4,100)
_Beep(5,4,100)
_Beep(6,4,100)
_Beep(12,4,100)
_Beep(6,4,100)
_Beep(3,5,100)
_Beep(12,4,100)
_Beep(9,4,100)
_Beep(6,4,100)
_Beep(5,4,100)
_Beep(6,4,100)
_Beep(8,3,100)
_Beep(1,4,100)
_Beep(4,4,100)
_Beep(8,4,100)
_Beep(1,5,100)
_Beep(8,4,100)
_Beep(7,4,100)
_Beep(8,4,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(9,4,100)
_Beep(8,4,100)
_Beep(9,4,100)
_Beep(8,3,100)
_Beep(10,3,100)
_Beep(7,4,100)
_Beep(1,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(7,5,100)
_Beep(1,5,100)
_Beep(10,5,100)
_Beep(7,5,100)
_Beep(4,5,100)
_Beep(1,5,100)
_Beep(12,4,100)
_Beep(1,5,100)
_Beep(8,3,1600)
_Beep(8,4,1600,100)
;=========================
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(10,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(12,5,100)
_Beep(10,5,100)
_Beep(12,5,100)
_Beep(8,5,100)
_Beep(12,5,100)
_Beep(10,5,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(10,5,100)
_Beep(8,5,100)
_Beep(10,5,100)
_Beep(7,5,100)
_Beep(10,5,100)
_Beep(8,5,100)
_Beep(10,5,100)
_Beep(12,5,100)
_Beep(8,5,100)
_Beep(7,5,100)
_Beep(8,5,100)
_Beep(3,5,100)
_Beep(8,6,100)
_Beep(6,6,100)
_Beep(8,6,100)
_Beep(9,6,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(3,6,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(8,6,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(12,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(8,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(9,5,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(8,5,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(6,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(9,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(8,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(10,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(12,5,100)
_Beep(10,5,100)
_Beep(12,5,100)
_Beep(8,5,100)
_Beep(12,5,100)
_Beep(10,5,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(10,5,100)
_Beep(8,5,100)
_Beep(10,5,100)
_Beep(7,5,100)
_Beep(10,5,100)
_Beep(8,5,100)
_Beep(10,5,100)
_Beep(12,5,100)
_Beep(8,5,100)
_Beep(7,5,100)
_Beep(8,5,100)
_Beep(3,5,100)
_Beep(8,6,100)
_Beep(6,6,100)
_Beep(8,6,100)
_Beep(9,6,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(3,6,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(8,6,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(12,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(8,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(9,5,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(8,5,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(6,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(9,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
_Beep(3,5,100)
;=========================
_Beep(8,6,100)
_Beep(6,6,100)
_Beep(8,6,100)
_Beep(9,6,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(3,6,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(8,6,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(12,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(8,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(9,5,100)
_Beep(6,6,100)
_Beep(4,6,100)
_Beep(6,6,100)
_Beep(8,5,100)
_Beep(4,6,100)
_Beep(3,6,100)
_Beep(4,6,100)
_Beep(6,5,100)
_Beep(3,6,100)
_Beep(1,6,100)
_Beep(3,6,100)
_Beep(4,5,100)
_Beep(1,6,100)
_Beep(12,5,100)
_Beep(1,6,100)
_Beep(9,5,100)
_Beep(6,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(4,5,100)
_Beep(3,5,100)
_Beep(4,5,100)
_Beep(6,5,100)
_Beep(3,5,100)
_Beep(1,5,100)
_Beep(3,5,100)
;=========================
_Beep(1,5,100)
_Beep(1,5,100)
_Beep(1,5,100)
_Beep(8,5,100)
_Beep(8,5,100)
_Beep(8,5,100)
_Beep(11,5,100)
_Beep(11,5,100)
_Beep(11,5,100)
_Beep(1,6,100)
_Beep(1,6,100)
_Beep(1,6,100)
_Beep(5,6,100)
_Beep(5,6,100)
_Beep(5,6,100)
_Beep(5,5,900)
_Beep(1,5,200)
_Beep(3,5,100)
_Beep(5,5,100)
_Beep(6,5,100)
_Beep(8,5,100)
_Beep(9,5,100)
_Beep(11,5,100)
_Beep(1,6,100)
_Beep(9,5,400)
_Beep(8,5,300)
_Beep(6,5,300)
_Beep(8,5,440)
_Beep(5,5,120)
_Beep(1,4,120)
_Beep(6,4,120)
_Beep(9,4,120)
_Beep(1,5,120)
_Beep(6,5,120)
_Beep(8,5,120)
_Beep(6,5,75)
_Beep(5,5,75)
_Beep(6,5,75)
_Beep(8,5,75)
_Beep(9,5,75)
_Beep(8,5,75)
_Beep(6,5,75)
_Beep(4,5,75)
_Beep(3,5,75)
_Beep(4,5,75)
_Beep(6,5,75)
_Beep(3,5,75)
_Beep(4,5,400)
_Beep(6,5,900)
_Beep(12,4,300)
_Beep(5,3,150,50)
_Beep(12,3,300)
_Beep(3,4,300)
_Beep(6,4,300)
_Beep(9,4,300)
_Beep(8,4,300)
_Beep(6,4,300)
_Beep(12,4,300)
_Beep(6,4,300)
_Beep(3,5,300)
_Beep(6,4,300)
_Beep(12,4,300)
_Beep(9,4,300)
_Beep(8,4,300)
_Beep(6,4,300)
_Beep(5,4,300)
_Beep(2,5,300)
_Beep(11,4,300)
_Beep(8,4,300)
_Beep(1,5,300)
_Beep(9,4,300)
_Beep(6,4,300)
_Beep(9,4,300)
_Beep(8,4,300)
_Beep(11,4,300)
_Beep(8,4,300)
_Beep(5,4,300)
_Beep(9,4,300)
_Beep(6,4,300)
_Beep(3,4,300)
_Beep(6,4,300)
_Beep(5,4,300)
_Beep(8,4,300)
_Beep(5,4,300)
_Beep(1,4,300)
_Beep(6,4,300)
_Beep(3,4,300)
_Beep(12,3,300)
_Beep(3,4,300)
_Beep(5,3,150,50)
_Beep(8,3,300)
_Beep(1,4,300)
_Beep(3,4,300)
_Beep(5,4,300)
_Beep(8,4,300)
_Beep(11,4,300)
_Beep(8,4,300)
_Beep(9,4,300)
_Beep(1,5,300)
_Beep(6,5,300)
_Beep(3,5,300)
_Beep(6,5,300)
_Beep(9,5,300)
_Beep(1,6,300)
_Beep(12,5,300)
_Beep(1,6,300)
_Beep(8,5,300)
_Beep(6,5,300)
_Beep(3,5,300)
_Beep(5,5,300)
_Beep(8,4,300)
_Beep(6,4,300)
_Beep(3,4,300)
_Beep(1,4,1200)
EndProcedure
OpenWindow(0,0,0,100,180,"",#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ButtonGadget(0,10,100,92,20,"Пуск трек")
ButtonGadget(1,10,125,92,20,"Стоп трек")
midiport=midiinit(#MOD_SWSYNTH)
If midiport >-1;есле есть программный синтезатор
If midiOutOpen(midiport,@hMidiOut,#CALLBACK_NULL)
;MidiOutMessage(hMidiOut,$B0, 0, $7E, #Channel1);ono Mode On,каждая следующая нота выключает предыдущию
MidiOutMessage(hMidiOut,$B0, #Channel1, $7F, 0);Polyphonic Mode On ,проигрывает ноты в канале одновременно
; MidiOutMessage(hMidiOut,$B0, 0, $7C, 0);Omni Mode Off
MidiOutMessage(hMidiOut,$E0, #Channel1, 50, 127);Pitch Bend Change (смена значения чувствительности Pitch Bend)
SetInstrument(#Channel1,0);Acoustic Grand Piano
EndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case 0
;pleysound()
pleysound2()
Case 1
MidiOutMessage(hMidiOut,$B0, 0, $7B, 0);All Notes Off
;MidiOutMessage(hMidiOut,$B0, 0, 120, 0);All Sounds Off
EndSelect
EndSelect
ForEver
midiOutClose(@hMidiOut)
End
EndIf
Вопрос хоть в полифонии и проигрывается много нот одновременно на канале(вроде бы до 32) но всёсравно будет некая задержка,как бы это их через отдельные потоки может,или нет смысла?
Поделиться530.07.2021 04:02:49
Sergeihik
балуюсь
чтобы остановить трек, нужно запустить в отдельном потоке от событий окна и внутри функции Beep проверять некий флаг остановки, который будет установлен кнопкой в окне.
Чтобы сделать так как на ютубе, надо открыть число каналов по количеству инструментов и в функцию ещё передавать номер канала. Да и вообще надо переделывать вид записи в виде массива данных, так как легко запутаться передавая ноты в общей последовательности в одной куче все инструменты. Возможно надо сделать несколько потоков и счётчик тактов, чтобы ноты включались по времени. Если система подвисла, тоже вопрос, пропустить ноты, что должны были быть проиграны или продолжать от места разморозки то что было на момент заморозки.
Отредактировано AZJIO (30.07.2021 04:29:16)
Поделиться630.07.2021 09:07:03
Не знаю, что выйдет из миди, но bytebeat более распространен
; http://rafb.net/paste/results/wMmfaj42.html
; Author: DarkDragon (updated for PB 4.00 by Andre)
; Date: 19. February 2006
; OS: Windows
; Demo: Yes
#SLen=10000*4*2
Structure WAVE
wFormatTag.w
nChannels.w
nSamplesPerSec.l
nAvgBytesPerSec.l
nBlockAlign.w
wBitsPerSample.w
cbSize.w
EndStructure
Structure WAVE_EX
RiffSig.l
RiffCount.l
WaveSig.l
fmtSig.l
TWaveFormat.l
w.WAVE
DataSig.l
DataCount.l
EndStructure
SampleRate = 11025
Global Dim SoundWaves.b(#SLen)
For t=1 To #SLen
SoundWaves(t) = t&(t>>8);t&t>>4|t>>7|t>>5|t>>14
Next
*m=AllocateMemory( #SLen+SizeOf(WAVE_EX) )
Bits=8
SoundDataSize=#SLen
If Bits = 0 : Bits = 8 : EndIf
If Bits > 32 : Bits = 32 : EndIf
WaveFormatEx.WAVE_EX
With WaveFormatEx
\RiffSig = $46464952
\RiffCount = SizeOf(WAVE_EX) + SoundDataSize
\WaveSig = $45564157
\fmtSig = $20746D66
\TWaveFormat = SizeOf(WAVE)
\w\wFormatTag = #WAVE_FORMAT_PCM
\w\nChannels = 1
\w\nSamplesPerSec = SampleRate
\w\wBitsPerSample = Bits
\w\nBlockAlign = (WaveFormatEx\w\nChannels * WaveFormatEx\w\wBitsPerSample) /8
\w\nAvgBytesPerSec = WaveFormatEx\w\nSamplesPerSec * WaveFormatEx\w\nBlockAlign
\w\cbSize = 0
\DataSig = $61746164
\DataCount = SoundDataSize
EndWith
CopyMemory(@WaveFormatEx, *m,SizeOf(WAVE_EX) )
CopyMemory(@SoundWaves(), *m+SizeOf(WAVE_EX), #SLen)
InitSound()
CatchSound(0,*m)
PlaySound(0,#PB_Sound_Loop)
MessageRequester("Press OK","n-joy",#PB_MessageRequester_Ok)
FreeSound(0)
FreeMemory(*m)
Поделиться731.07.2021 04:16:21
Рещил почитать пока про формат миди файла,оказалось что данные лежат типа перевёрнутых.ну это пока заголовок изучаю.
вобщем кнопку на загрузку сделал файла
Structure Midi_zagolovok
MThd.i;заголовок
Dlina_zapisi.i;длинна последующая после этих 8 байтов
Format_midi.w;3 формата 0=данные записаны на одном треке(возможно на 16-и каналах),1-в нескольких отдельных,2-несколько независимых
NumTrek.w; количество записей MTRK количество треков в файле
PPQN.w;временные тики
EndStructure
Procedure Revers_i(*adres)
!mov dword eax,[p.p_adres]
!ror word [eax],8
!ror dword [eax],16
!ror word [eax],8
EndProcedure
Procedure Revers_w(*adres)
!mov dword eax,[p.p_adres]
!ror word [eax],8
EndProcedure
Procedure Open_midi()
Protected *Midi_zagolovok.Midi_zagolovok
Protected OpenFile.s,TextHnd.l,Textlg.l,*mem
OpenFile.s=OpenFileRequester("Открыть файл", "", "*.txt, *.midi|*.txt.midi|All Files|*.*", 0);диалог
If OpenFile<>"";если имя файла 1 и более символа
TextHnd=OpenFile(#PB_Any,OpenFile)
If TextHnd
Textlg=Lof(TextHnd)
If Textlg>0
*mem=AllocateMemory(TextHnd)
ReadData(TextHnd,*mem,Textlg)
*Midi_zagolovok=*mem
Revers_i(@*Midi_zagolovok\Dlina_zapisi)
; i=*Midi_zagolovok\Dlina_zapisi
Debug PeekS(@*Midi_zagolovok\MThd,4,#PB_Ascii)
; Debug i
Debug Str(PeekI(@*Midi_zagolovok\Dlina_zapisi))
; Debug Str(PeekI(@*Midi_zagolovok\MThd+4))
;Debug Str(PeekI(@*Midi_zagolovok\Dlina_zapisi+4));следующая запись
; Debug Str(PeekI(*Midi_zagolovok+8+*Midi_zagolovok\Dlina_zapisi));следующая запись
Revers_w(@*Midi_zagolovok\Format_midi)
Debug Str(PeekW(@*Midi_zagolovok\Format_midi))
;
Revers_w(@*Midi_zagolovok\NumTrek)
Debug Str(PeekW(@*Midi_zagolovok\NumTrek))
;
Revers_w(@*Midi_zagolovok\PPQN)
Debug Str(PeekW(@*Midi_zagolovok\PPQN))
FreeMemory(*mem)
CloseFile(TextHnd)
EndIf
Else
MessageRequester("Открытие файла","Не удалось открыть файл!",#MB_OK | #MB_ICONERROR)
EndIf
EndIf
EndProcedure
Отредактировано Sergeihik (31.07.2021 04:55:44)
Поделиться801.08.2021 22:21:37
встраивают микросхему синтезатора
А её никогда не встраивали.
Для этого всегда были звуковые карты.
Касаемо операционок, начиная с XP в Винде вполне приличный программный синтезатор.
Если Вас интересует парсинг миди-файла, так это малость не синтез.
Когда-то занимался этим вопросом.
В результате такую вот программулину написАл.
наподобие этого
В таком виде абсолютно бесполезное.
Поделиться902.08.2021 15:07:21
Паркинг это только. Как понимание как проигрывать данные и на этом выстроить своё нужное в программе,как то так.
Поделиться1003.08.2021 18:31:40
Паркинг это только
Я, когда изучал структуру миди-файлов, уже давно и хорошо был знаком с протоколом МИДИ.
Без предварительной подготовки, боюсь, будет сложновато.
Например, самый распространённый формат миди-файлов (формат 1) сохраняет всю структуру треков секвенсора.
Основа довольно простая: идут временные интервалы (в относительном формате), и далее события, которые надо отправить.
Сложности заключаются в том, что все эти треки надо объединить в единое целое.
Плюс ещё всякая служебная информация.
В сети должно быть подробное описание формата.
Ну, а отправка событий - это уже отдельная тема.
Поделиться1104.08.2021 03:32:45
Sergeihik
Если удастся разобраться в форматах MIDI пиши, я сам горел идеей сделать разбор MIDI-файла, чтобы была возможность в своей программе проиграть некую мелодию, то есть упростить реализацию всякие пичбенды исключить и вывести например чистую мелодию на динамик ПК. Потому что ранее, чтобы для своей функции Beep, чтобы создать мелодию нужно открывать MIDI например в какой нибудь "Cakewalk Music Creator", чтобы визуально видеть длительности/паузы и высоту нот. А мелодии можно найти на midi.ru, кто-то даже время от времени выкладывал пол-гига midi-файлов с midi.ru.
Поделиться1204.08.2021 10:51:11
чтобы была возможность в своей программе проиграть некую мелодию
Чем трекерная музыка не подошла?
If InitSound() = 0
MessageRequester("Ошибка", "Звуковая система недоступна.") : End
EndIf
FileName$ = OpenFileRequester("","","Музыкальные модули (*.mod, *.xm, *.it)|*.mod;*.xm;*.it", 0)
If FileName$
If LoadMusic(0, FileName$)
PlayMusic(0)
MessageRequester("PureBasic - Module проигрыватель", "Воспроизведение музыкального модуля...")
Else
MessageRequester("Ошибка", "Не удается загрузить музыкальный модуль или неверный формат модуля.")
EndIf
EndIf
Несколько файлов для теста. https://dropfiles.ru/download/8d80d40f1 … 346d6.html
Поделиться1304.08.2021 10:52:50
Чем трекерная музыка не подошла?
Кстати, попадались примеры парсера midi, но на многих файликах просто давились.
Поделиться1404.08.2021 20:51:05
Коллеги, давайте уже отделим мягкое от тёплого.
Есть два больших вопроса:
- Формат миди-файлов
- Воспроизведение миди-сообщений через миди-подсистему операционки.
Что надо?
Поделиться1505.08.2021 07:52:50
- Воспроизведение миди-сообщений через миди-подсистему операционки.
Что надо?
уже сказано
Поделиться1629.08.2021 13:52:45
Накидал немного кода,проигрывает на канальных сообщениях и треки последовательно пока.
Structure hMidiOut;тупо для ссылки на процедуры
hMidiOut.i
EndStructure
;
Structure Mtrk
Mtrk.i;заголовок блока трека
Dlina_treka.l;блока mtrk за этими 8 байт заголовка
EndStructure
Structure Midi_zagolovok
MThd.i;заголовок
Dlina_zapisi.i;длинна последующая после этих 8 байтов
Format_midi.w;3 формата 0=данные записаны на одном треке(все сообщения со всех MIDI-каналов в одном треке),1-в нескольких отдельных,2-несколько независимых
NumTrek.w; количество записей MTRK, количество блоков (треков) в файле,(первый карта темпа)
PPQN.w;временные тики
EndStructure
Global hMidiOut.i
Global midiport.i
Procedure Error(funkciy$,ohibka.i)
Select ohibka
Case #MIXERR_BASE
MessageRequester(funkciy$,"Минимальное значение кода ошибки микшера")
Case #MIXERR_INVALLINE
MessageRequester(funkciy$,"Недопустимый индекс/идентификатор линии")
Case #MIXERR_INVALCONTROL
MessageRequester(funkciy$,"Недопустимый индекс/идентификатор элемента управления")
Case #MIXERR_INVALVALUE
MessageRequester(funkciy$,"Недопустимое значение элемента управления")
Case #MIXERR_LASTERROR
MessageRequester(funkciy$,"Максимальное значение кода ошибки микшера")
Case #MMSYSERR_ALLOCATED
MessageRequester(funkciy$,"Устройство занято другим приложением")
Case #MMSYSERR_BADDEVICEID
MessageRequester(funkciy$,"Недопустимый номер устройства")
Case #MMSYSERR_NOTENABLED
MessageRequester(funkciy$,"Драйвер не активизирован")
Case #MMSYSERR_INVALFLAG
MessageRequester(funkciy$,"Один или несколько флагов недействительны.")
Case #MMSYSERR_INVALHANDLE
MessageRequester(funkciy$,"Недопустимый дискриптор открытого устройства")
Case #MMSYSERR_INVALPARAM
MessageRequester(funkciy$,"Один или несколько параметров недействительны.")
Case #MMSYSERR_NODRIVER
MessageRequester(funkciy$,"Драйвер отсутствует")
Case #MMSYSERR_NOMEM
MessageRequester(funkciy$,"Недостаточно памяти для выделения")
Case #MMSYSERR_NOTSUPPORTED
MessageRequester(funkciy$,"Запрошенная функция не поддерживается")
Case #MMSYSERR_HANDLEBUSY
MessageRequester(funkciy$,"Над ключом выполняется операция от другой задачи (thread)")
Case #MMSYSERR_INVALIDALIAS ;13
Case 14;#MMSYSERR_BADDB ;14
Case 15;#MMSYSERR_KEYNOTFOUND ;15
Case 16;#MMSYSERR_READERROR ;16
Case 17;#MMSYSERR_WRITEERROR; 17
Case 18;#MMSYSERR_DELETEERROR ;18
Case 19;#MMSYSERR_VALNOTFOUND ;19
Case 20;#MMSYSERR_NODRIVERCB
;MessageRequester(funkciy$,"Драйвер не выполнил уведомления (callback)")
Case #MMSYSERR_BADERRNUM
MessageRequester(funkciy$,"Код ошибки вне допустимого диапазона")
Case #MMSYSERR_ERROR
MessageRequester(funkciy$,"Неопределенная ошибка")
EndSelect
EndProcedure
Procedure.i midiinit(Konstanta.i)
Protected midi.MIDIOUTCAPS
Protected devnum
#MOD_MIDIPORT =1;Аппаратный порт MIDI.
#MOD_SYNTH =2;Синтезатор
#MOD_SQSYNTH=3;Синтезатор прямоугольных импульсов.
#MOD_FMSYNTH=4;FM-синтезатор.
#MOD_MAPPER =5;Microsoft MIDI маппер.
#MOD_WAVETABLE=6;Аппаратный волновой синтезатор.
#MOD_SWSYNTH=7 ;Программный синтезатор
If midiOutGetNumDevs_();извлекает количество MIDI-устройств вывода,0=нет устройств
For devnum=0 To 7
If midiOutGetDevCaps_(devnum,@midi,SizeOf(MIDIOUTCAPS))=0
Debug midi\wTechnology;что есть
If midi\wTechnology=Konstanta;#MOD_SWSYNTH
Debug PeekS(@midi\szPname,-1,#PB_Unicode);Название продукта в строке с нулевым символом в конце.
Debug midi\wVoices;количество голосов
Debug midi\wNotes ;количество одновременных нот, которые могут быть воспроизведены
Debug midi\wChannelMask;Портовые устройства, которые передают по всем каналам, устанавливают этот элемент в 0xFFFF.
Debug midi\dwSupport;Дополнительный функционал, поддерживаемый устройством(MIDICAPS_VOLUME=1 Поддерживает регулировку громкости.)
ProcedureReturn devnum
EndIf
EndIf
Next
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i midiOutOpen(midiport.i,*hMidiOut.hMidiOut,flagi.i,dwCallback.i=0,CallbackInstance.i=0);открывает выходное MIDI-устройство
Protected result.i
result=midiOutOpen_(*hMidiOut.hMidiOut,midiport,dwCallback,CallbackInstance,flagi)
If result=MMSYSERR_NOERROR
ProcedureReturn 1
Else
Error("Error midiOutOpen()",result)
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i midiOutClose(*hMidiOut);получаем дискриптор устройства
Protected MidiOut.i
!mov dword eax,[p.p_hMidiOut]
!mov dword eax,[eax]
!mov dword [p.v_MidiOut],eax
If midiOutClose_(MidiOut)=#MMSYSERR_NOERROR
!mov dword eax,[p.p_hMidiOut]
!mov dword [eax],0
ProcedureReturn 1
Else
MessageRequester("Error midiOutClose()","INVALIDE_HANDLE hMidiOut")
ProcedureReturn 0
EndIf
EndProcedure
Procedure Revers_i(*adres)
!mov dword eax,[p.p_adres]
!ror word [eax],8
!ror dword [eax],16
!ror word [eax],8
EndProcedure
Procedure Revers_w(*adres)
!mov dword eax,[p.p_adres]
!ror word [eax],8
EndProcedure
Procedure MidiOutMesage(hMidi,iStatus,iData1,iData2)
Protected dwMessage.i
dwMessage = iStatus | (iData1 << 8 ) | (iData2 << 16)
ProcedureReturn midiOutShortMsg_(hMidi, dwMessage)
EndProcedure
Procedure Open_midi()
Protected OpenFile.s
Protected light.l
Protected *Midi_zagolovok.Midi_zagolovok
Protected *Mtrk.Mtrk
Protected kolihestvoMtrk.l
Protected dlinaMtrk.i
Protected time.w
Static *mem
Protected *sobytie
Protected delta_time_sobytie.i
Protected delta_kolihestvoBait.a
Protected baitsobytiy.a
OpenFile.s=OpenFileRequester("Открыть файл", "", "*.midi|*.midi|All Files|*.*", 0);диалог
If OpenFile<>"";если имя файла 1 и более символа
If ReadFile(0, OpenFile)
light=Lof(0)
If light>0
*mem=AllocateMemory(light)
Debug *mem
If *mem
Debug ReadData(0,*mem,light)
CloseFile(0)
;============================== обработка памяти
*Midi_zagolovok=*mem
Debug PeekS(@*Midi_zagolovok\MThd,4,#PB_Ascii)
Revers_i(@*Midi_zagolovok\Dlina_zapisi)
Debug Str(PeekI(@*Midi_zagolovok\Dlina_zapisi))
;
Revers_w(@*Midi_zagolovok\Format_midi)
Debug Str(PeekW(@*Midi_zagolovok\Format_midi))
;
Revers_w(@*Midi_zagolovok\NumTrek)
kolihestvoMtrk=PeekW(@*Midi_zagolovok\NumTrek)
Debug "kolihestvoMtrk "+Str(kolihestvoMtrk)
;Debug Str(PeekW(@*Midi_zagolovok\NumTrek))
;
;Debug Str(PeekW(@*Midi_zagolovok\PPQN))
;Revers_w(@*Midi_zagolovok\PPQN)
time=PeekW(@*Midi_zagolovok\PPQN)
;Debug time
; !shr word[p.v_time],15
If time & $8000;Если старший бит установлен в единицу, то используется абсолютный способ
; Debug "tttttttttt"
; time=PeekW(@*Midi_zagolovok\PPQN)
time>>8
time & $7F;обнулить включая старший бит =количество тиков в четверти(допустим 96)
;!shr word[p.v_time],8
;time>>8
EndIf
Debug time
;time*2
;Debug Str(PeekW(@*Midi_zagolovok\PPQN))
;
If PeekS(@*Midi_zagolovok\MThd,4,#PB_Ascii)="MThd"
Select PeekW(@*Midi_zagolovok\Format_midi);format
Case 0
Case 1
;{;format 1
*sobytie=*mem
*sobytie+14
cikl3:
If kolihestvoMtrk>0
*Mtrk=*sobytie
Debug PeekS(@*Mtrk\Mtrk,4,#PB_Ascii)
If PeekS(@*Mtrk\Mtrk,4,#PB_Ascii)="MTrk"
Revers_i(@*Mtrk\Dlina_treka);могут быть сообщения разной длинны
Debug PeekI(@*Mtrk\Dlina_treka)
dlinaMtrk=PeekI(@*Mtrk\Dlina_treka)
If dlinaMtrk>0
*sobytie+8;*Mtrk+8
cikl:
;Debug *mem
;Debug PeekA(*sobytie);;следущий байт за заголовком mtrk (пошли события)
;сначала указано время события
If PeekA(*sobytie) & $80;время события по дельте времени в одном байте
delta_kolihestvoBait=2
zikl:
*sobytie+1
If PeekA(*sobytie) & $80
delta_kolihestvoBait+1
Goto zikl
EndIf
*sobytie+1
Else;иначе в байтах переменной длинны
*sobytie+1
delta_kolihestvoBait=1
EndIf
Debug "delta_kolihestvoBait "+Str(delta_kolihestvoBait)
If delta_kolihestvoBait=1
delta_time_sobytie=PeekA(*sobytie-1)
ElseIf delta_kolihestvoBait=2
delta_time_sobytie=PeekW(*sobytie-2)
!ror word [p.v_delta_time_sobytie],8
EndIf
Debug "delta_time_sobytie "+Str(delta_time_sobytie)
;=========события========
baitsobytiy=PeekA(*sobytie);статус байт события
cikl5:
Debug "baitsobytiy "+Hex(baitsobytiy)
If baitsobytiy=$FF;{;мета события (17-ть мета событий-?)
*sobytie+1
baitsobytiy=PeekA(*sobytie);
Debug "Мета событие "+Hex(baitsobytiy)
If baitsobytiy=0;{;Sequence Number
;Это необязательное мета-событие имеет структуру, показанную на рис. 20. Оно задает номер секвенции (паттерна), на который можно
;ссылаться в дальнейшем при помощи сообщений MIDI Cueing. В таком виде это мета-событие имеет смысл только для формата 2, поскольку
;в файлах формата 0 и 1 есть только одна секвенция (то есть целая композиция). Событие должно располагаться в начале трека, перед
;любым событием с ненулевым дельта-временем, и перед любым другим MIDI-событием. Если номер секвенции опущен, то считается
;что секвенции (паттерны) следуют в порядке расположения блоков трека в файле. Если необходимо сохранить несколько многотрековых
;композиций в виде группы файлов формата 0 или 1, то событие Sequence Number может использоваться в качестве номера файла.
*sobytie+4
Goto cikl
;};
ElseIf baitsobytiy=1;{;Text Event
Debug "fffffffff111111111_Text Event"
Debug PeekA(*sobytie+1)
Debug PeekS(*sobytie+2,PeekA(*sobytie+1),#PB_Ascii)
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=2;{;Содержит заметку об авторских правах.
;Заметка должна содержать символы "(", "C" и ")", год и владельца авторских прав. Если в одном файле содержатся несколько произведений, все заметки об авторских правах должны быть размещены в начале файла. Заметка должна быть первым событием в первом блоке трека в момент времени 0.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=3;{;Содержит название произведения
;если находится в файле формата 0 или в первом блоке трека в файле формата 1), в остальных случаях — название трека.
*sobytie+1
Debug PeekA(*sobytie);следующая длина в байтах (название произведения)
Debug PeekS(*sobytie+1,PeekA(*sobytie),#PB_Ascii);
*sobytie+PeekA(*sobytie)+1
Goto cikl;смотрим следующие событие
;};
ElseIf baitsobytiy=4;{;Содержит название инструмента, которым должен исполняться трек.
Debug "инструмент "+PeekS(*sobytie+2,PeekA(*sobytie+1),#PB_Ascii)
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=5;{;Lyric/Display Meta Event.
;Задает слова песни, которые должны быть исполнены в указанное время. Обычно каждый слог представлен отдельным событием Lyric,
;то есть для каждого слога четко задано время исполнения. В 1997 году организация MMA расширила это событие, добавив команды
;форматирования при выводе текста на экран, поддержку многобайтовой кодировки символов и Unicode, а также информацию о произведении
;(название, композитор, исполнитель). Расширенное мета-событие Lyric предложено называть Lyric/Display Meta Event.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=6;{;Marker
;Событие располагается обычно на первом блоке трека в файле формата 1 (или на единственном треке формата 0).
;Определяет позицию внутри произведения и одновременно задает ее имя.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=7;{;Задает точку привязки партитуры
;;Задает точку привязки партитуры к моменту кино-, видео- или сценического действия и одновременно описание момента
;(например, "Машина въехала в дерево", "Герой получил пощечину").
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=8;{;Program Name
;Это мета-событие служит для визуальной ориентировки и информирования пользователя об используемом имени пэтча на данном канале.
;Непосредственно за этим событием должны следовать события Bank Select и Program Change, посредством которым реально выбирается
;пэтч. Если на протяжении звучания трека на том же MIDI-канале изменяется пэтч, событие
;Program Name может встречаться перед каждым таким изменением.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;}
ElseIf baitsobytiy=9;{;Это мета-событие позволяет в одном MIDI-файле задать несколько устройств воспроизведения (тон-генераторов)
;то есть реализовать более 16 MIDI-каналов.Например, в аранжировке могут быть задействованы два тон-генератора
;первый подключен к порту "MIDI Out 3" интерфейса, второй — к порту "MIDI Out 4"
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=$20;{;MIDI Channel Prefix
;Поскольку SysEx-события и мета-события не содержат в статус-байте номер MIDI-канала, нужен способ привязки этих событий
;к MIDI-каналу.Событие MIDI Channel Prefix содержит номер MIDI-канала,с которым ассоциируются все последующие SysEx- и мета-события
;Канал, заданный таким образом, остается действительным до следующего нормального MIDI-события (которое содержит номер канала)
;или до следующего мета-события MIDI Channel Prefix.
;Если каждый трек в секвенсоре соответствует одному MIDI-каналу, то при записи аранжировки в формате 0 это мета-событие помогае
;т сохранить связь мета-событий с конкретным треком. Подобная возможность предусмотрена и в формате файлов Yamaha ESEQ.
Debug "префикс канала "+PeekA(*sobytie+2)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=$21;{;MIDI Port
;Это необязательное событие, которое обычно происходит в начале MTrk (т. Е. Перед любым
;ненулевое дельта-время и перед любыми событиями midi) указывает, из какого порта MIDI (т. е.
;buss) MIDI-события в MTrk go. Байт данных pp, это номер порта, где 0
;будет первой шиной MIDI в системе.
;Спецификация MIDI имеет ограничение в 16 MIDI-каналов на вход / выход MIDI (т. Е. Порт, шина,
;jack, или любую другую терминологию, которую вы используете для описания оборудования для одного MIDI-входа /
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=$2F;{;End of Track
;Это обязательное мета-событие (рис. 23) указывает момент окончания трека. Должно быть последним событием внутри блока трека.
;Точный момент окончания трека необходим секвенсорам для возможности воспроизведения трека в цикле или стыковки его с другим треком
kolihestvoMtrk-1
*sobytie+2
;Debug "kolihestvoMtrk "+Str(kolihestvoMtrk)
Goto cikl3
;};
ElseIf baitsobytiy=$51;{;Set Tempo,
;Задает текущий темп в необычном измерении — микросекунды на четверть. Представление темпа в виде "время на четверть"
;вместо "четверть за время" позволяет осуществить точную долговременную синхронизацию при работе по протоколу MTC или SMPTE.
;Так, если число тиков 3240, темп 120 BPM (500000 мкс на четверть), 96 тиков в четверти (96 PPQN), время в миллисекундах
;равно 3240 x (500000/96(PPQN)) / 1000 = 16875 мс (или 16,875 с).
Protected temp.i
temp=PeekA(*sobytie+4)|(PeekA(*sobytie+3)<<8)|(PeekA(*sobytie+2)<<16)
temp/time;(PPQN)
Debug temp
*sobytie+5;bait peremennogo razmera i dannye
Goto cikl
;}
ElseIf baitsobytiy=$54;{;SMPTE Offset
;Это необязательное мета-событие задает время SMPTE, с которого начинается трек. Событие должно располагаться в начале трека
;перед любым другим событием с ненулевым дельта-временем, и перед любым MIDI-событием. В файле формата 1 смещение SMPTE должно
;храниться с картой темпа на первом треке. Поле ff содержит сотые доли кадра, даже в том случае, если в блоке заголовка определено
;другое количество тиков на кадр.
*sobytie+7
Goto cikl
;};
ElseIf baitsobytiy=$58;{;Time Signature,Событие задает музыкальный размер,
*sobytie+6
Goto cikl
;};
ElseIf baitsobytiy=$59;{;Key Signature
;Событие задает текущую тональность (точнее, ладотональность — высоту и наклонение лада, мажор/минор)
*sobytie+4
Goto cikl
;};
ElseIf baitsobytiy=$7F;{;Sequencer-Specific Meta-Event
;применяется аналогично системным эксклюзивным сообщениями в протоколе MIDI. То есть, позволяет записывать в MIDI-файл информацию
;специфичную для конкретного секвенсора. Длина события выражается переменным способом. Первый байт данных (или три байта)
;содержат ID производителя. Остальной формат события определяется конкретным производителем под конкретную программу или семейство
;программ.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
EndIf
;};
ElseIf baitsobytiy=$F0;sysEx-сообщение
ElseIf baitsobytiy=>$90 And baitsobytiy<=$9F;{;nota on
delta_time_sobytie*temp/1000000
Debug delta_time_sobytie
Delay(delta_time_sobytie)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
;Delay(delta_time_sobytie)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$80 And baitsobytiy<=$8F;{;nota off
delta_time_sobytie*temp/1000000
Delay(delta_time_sobytie)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
;Delay(delta_time_sobytie)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$C0 And baitsobytiy<=$CF;{;Событие SetInstrument(установка инструмента в каналы)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),0);следущий байт собственно номер инструмента
Debug Hex(PeekA(*sobytie+1))
*sobytie+2
Goto cikl
;};
ElseIf baitsobytiy=>$A0 And baitsobytiy<=$AF;{;
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$B0 And baitsobytiy<=$BF;{;Специальные канальные сообщения,Задаются контpоллеpами 120..127 и упpавляют обpаботкой сообщений в каналах:
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$D0 And baitsobytiy<=$DF;{;манипуляция после нажатия клавиши(давление в канале)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$E0 And baitsobytiy<=$EF;{;Pitch Bend Change (смена значения чувствительности для каналов Pitch Bend)изменение высоты звука
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Goto cikl
;};
;ElseIf baitsobytiy=>$08 And baitsobytiy<=$7f;не ясно что за сообщение(я)типа перевёрнутый статус байт?
; !ror byte[p.v_baitsobytiy],4
; MidiOutMesage(hMidiOut,baitsobytiy,PeekA(*sobytie+1),PeekA(*sobytie+2))
;*sobytie+3
; Goto cikl5
EndIf
EndIf
EndIf
EndIf
;};
Case 2;format 2
EndSelect
EndIf
;==============================
Debug *mem
FreeMemory(*mem)
EndIf
EndIf
Else
MessageRequester("Открытие файла","Не удалось открыть файл!",#MB_OK | #MB_ICONERROR)
EndIf
EndIf
EndProcedure
OpenWindow(0,0,0,100,180,"",#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ButtonGadget(2,10,5,92,20,"Open midi")
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case 2
midiport=midiinit(#MOD_SWSYNTH)
If midiport>-1;есле есть программный синтезатор
If midiOutOpen(midiport,@hMidiOut,#CALLBACK_NULL)
Open_midi()
midiOutClose(@hMidiOut)
EndIf
EndIf
EndSelect
EndSelect
ForEver
End
Миди файлы можно отсюда скачать Ссылка
Отредактировано Sergeihik (29.08.2021 15:38:09)
Поделиться1703.09.2021 14:00:13
Sergeihik
Не понял, зачем тебе метки Goto? Делаешь цикл, а вместо Goto используешь Continue. Я не разбирался во всех перипетиях кода, но знаю что любой код можно написать правильно, не переходом Goto, а вызовом функции. И это всегда выглядит логичней, потому что ты даёшь пользователю читающему код понять, что это цикловой повтор с прерываниями цикла, а меткой Goto ничего невозможно дать понять.
Поделиться1804.09.2021 11:48:28
В таком варианте тогда будет без конечный цикл с выходом в конце трека и снова возврат на раскрутку трека ,есть там ещё длина трека но я не разбирался там количество команд или длинна байтов вот от этого тоже можно сделать цикл.я же пока хочу понять по командам и времени исполнения ну и типа взять команды в память и оттуда воспроизвести одновременно несколько треков.
Поделиться1904.09.2021 13:31:29
Sergeihik
Может тебе Inc_MIDI.pbi чем-то поможет?
Это же элементарно переписывается в цикл
zikl: *sobytie+1 If PeekA(*sobytie) & $80 delta_kolihestvoBait+1 Goto zikl EndIf *sobytie + 1 While PeekA(*sobytie) & $80 *sobytie + 1 delta_kolihestvoBait + 1 Wend delta_kolihestvoBait - 1 ; переменную можно заранее задать минусанув единицу Repeat *sobytie + 1 delta_kolihestvoBait + 1 Until Not PeekA(*sobytie) & $80
И никакого возврата с начала не получится, так как это ТОЧНАЯ копия событий с метками.
If OpenFile<>"" If Asc(OpenFile) ; так проверяет наличие первой буквы в строке
не проверял, но вот набросал на циклах
Repeat
If kolihestvoMtrk>0
*Mtrk=*sobytie
Debug PeekS(@*Mtrk\Mtrk,4,#PB_Ascii)
If PeekS(@*Mtrk\Mtrk,4,#PB_Ascii)="MTrk"
Revers_i(@*Mtrk\Dlina_treka);могут быть сообщения разной длинны
Debug PeekI(@*Mtrk\Dlina_treka)
dlinaMtrk=PeekI(@*Mtrk\Dlina_treka)
If dlinaMtrk>0
*sobytie+8;*Mtrk+8
Repeat
;Debug *mem
;Debug PeekA(*sobytie);;следущий байт за заголовком mtrk (пошли события)
;сначала указано время события
If PeekA(*sobytie) & $80;время события по дельте времени в одном байте
delta_kolihestvoBait=1
Repeat
*sobytie + 1
delta_kolihestvoBait + 1
Until Not PeekA(*sobytie) & $80
*sobytie+1
Else;иначе в байтах переменной длинны
*sobytie+1
delta_kolihestvoBait=1
EndIf
Debug "delta_kolihestvoBait "+Str(delta_kolihestvoBait)
If delta_kolihestvoBait=1
delta_time_sobytie=PeekA(*sobytie-1)
ElseIf delta_kolihestvoBait=2
delta_time_sobytie=PeekW(*sobytie-2)
!ror word [p.v_delta_time_sobytie],8
EndIf
Debug "delta_time_sobytie "+Str(delta_time_sobytie)
;=========события========
baitsobytiy=PeekA(*sobytie);статус байт события
; cikl5:
Debug "baitsobytiy "+Hex(baitsobytiy)
Select baitsobytiy;{;мета события (17-ть мета событий-?)
Case $FF
*sobytie+1
baitsobytiy=PeekA(*sobytie);
Debug "Мета событие "+Hex(baitsobytiy)
Select baitsobytiy
Case 0
*sobytie+4
Continue
;};
Case 1;{;Text Event
Debug "fffffffff111111111_Text Event"
Debug PeekA(*sobytie+1)
Debug PeekS(*sobytie+2,PeekA(*sobytie+1),#PB_Ascii)
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case 2;{;Содержит заметку об авторских правах.
;Заметка должна содержать символы "(", "C" и ")", год и владельца авторских прав. Если в одном файле содержатся несколько произведений, все заметки об авторских правах должны быть размещены в начале файла. Заметка должна быть первым событием в первом блоке трека в момент времени 0.
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case 3;{;Содержит название произведения
;если находится в файле формата 0 или в первом блоке трека в файле формата 1), в остальных случаях — название трека.
*sobytie+1
Debug PeekA(*sobytie);следующая длина в байтах (название произведения)
Debug PeekS(*sobytie+1,PeekA(*sobytie),#PB_Ascii);
*sobytie+PeekA(*sobytie)+1
Continue;смотрим следующие событие
;};
Case 4 ;{;Содержит название инструмента, которым должен исполняться трек.
Debug "инструмент "+PeekS(*sobytie+2,PeekA(*sobytie+1),#PB_Ascii)
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case 5;{;Lyric/Display Meta Event.
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case 6;{;Marker
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case 7;{;Задает точку привязки партитуры
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case 8;{;Program Name
*sobytie+PeekA(*sobytie+1)+2
Continue
;}
Case 9;{;
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
Case $20;{;MIDI Channel Prefix
Debug "префикс канала "+PeekA(*sobytie+2)
*sobytie+3
Continue
;};
Case $21;{;MIDI Port
*sobytie+3
Continue
;};
Case $2F;{;End of Track
kolihestvoMtrk-1
*sobytie+2
;Debug "kolihestvoMtrk "+Str(kolihestvoMtrk)
Break
;};
Case $51;{;Set Tempo,
Protected temp.i
temp=PeekA(*sobytie+4)|(PeekA(*sobytie+3)<<8)|(PeekA(*sobytie+2)<<16)
temp/time;(PPQN)
Debug temp
*sobytie+5;bait peremennogo razmera i dannye
Continue
;}
Case $54;{;SMPTE Offset
*sobytie+7
Continue
;};
Case $58;{;Time Signature,Событие задает музыкальный размер,
*sobytie+6
Continue
;};
Case $59;{;Key Signature
;Событие задает текущую тональность (точнее, ладотональность — высоту и наклонение лада, мажор/минор)
*sobytie+4
Continue
;};
Case $7F;{;Sequencer-Specific Meta-Event
*sobytie+PeekA(*sobytie+1)+2
Continue
;};
EndSelect
;};
Case $F0;sysEx-сообщение
Case $90 To $9F;{;nota on
delta_time_sobytie*temp/1000000
Debug delta_time_sobytie
Delay(delta_time_sobytie)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
;Delay(delta_time_sobytie)
*sobytie+3
Continue
;};
Case $80 To $8F;{;nota off
delta_time_sobytie*temp/1000000
Delay(delta_time_sobytie)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
;Delay(delta_time_sobytie)
*sobytie+3
Continue
;};
Case $C0 To $CF;{;Событие SetInstrument(установка инструмента в каналы)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),0);следущий байт собственно номер инструмента
Debug Hex(PeekA(*sobytie+1))
*sobytie+2
Continue
;};
Case $A0 To $AF;{;
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Continue
;};
Case $B0 To $BF;{;Специальные канальные сообщения,Задаются контpоллеpами 120..127 и упpавляют обpаботкой сообщений в каналах:
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Continue
;};
Case $D0 To $DF;{;манипуляция после нажатия клавиши(давление в канале)
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Continue
;};
Case $E0 To $EF;{;Pitch Bend Change (смена значения чувствительности для каналов Pitch Bend)изменение высоты звука
MidiOutMesage(hMidiOut,PeekA(*sobytie),PeekA(*sobytie+1),PeekA(*sobytie+2))
*sobytie+3
Continue
EndSelect
Break 2 ; при отсутсвии ожного из событий ранее перечисленных, т.е. закрытия Select выпрыгиваем из 2-х циклов, кстати можно сделать по Default
ForEver
Continue ; для события $2F по Break переходим к началу цикла
EndIf
EndIf
EndIf
ForEverНасколько я знал ранее в отличии от меток, цикл надёжно контролируется отладчиком, так как есть начало и конец блока, а в метках прерывание кода неизвестно где с прыжком в неизвестно куда.
Отредактировано AZJIO (04.09.2021 15:17:35)
Поделиться2004.09.2021 15:59:23
Есле цикл то возможно лучше брать длинну трека за основу так как вдруг не окажется байта завершения трека?,но сейчас мне как бы это не принципиально хочется с временем проигрывания разобраться.
PS:Скачал прогу Anvil Studio, в ней можно сохранить треки в формат 0(воспроизведение всех треков(каналов)в один поток).
на раскрутку команд просто поставить case 0,1
Отредактировано Sergeihik (04.09.2021 16:00:13)
Поделиться2104.09.2021 19:01:56
Да ещё для проигрывания и синхронизации как я понял используются высокоточные таймеры для мультимедиа.
Global TIMECAPS.TIMECAPS timeGetDevCaps_(@TIMECAPS,SizeOf(TIMECAPS));получает разрешение таймера от минимума до максимума ;Минимальное разрешение таймера в миллисекундах для приложения или драйвера устройства. Меньшее значение указывает более высокое (более точное) разрешение. Debug TIMECAPS\wPeriodMin Debug TIMECAPS\wPeriodMax ;Замечания ;Вызовите эту функцию непосредственно перед использованием служб таймера и вызовите функцию timeEndPeriod сразу после завершения использования служб таймера. timeBeginPeriod_(TIMECAPS\wPeriodMin);запрашивает минимальное разрешение для периодических таймеров. timeEndPeriod_(TIMECAPS\wPeriodMin);очищает ранее установленное минимальное разрешение таймера.
PS:Из справки.
Эти службы таймера(ну и другие функции) полезны для приложений, которым требуется синхронизация с высоким разрешением. Например, MIDI-секвенсору требуется таймер с высоким разрешением, потому что он должен поддерживать темп MIDI-событий с разрешением в 1 миллисекунду.
Отредактировано Sergeihik (04.09.2021 19:07:31)
Поделиться2206.09.2021 20:54:54
Вобщем справка ссылает ся что time setevent устарела и нужно использовать CreateTimerQueue
какой то код попался и перевёл на скору руку но оказалось нет таких в пурике функций
буду подгружать и дальше копать и изучать их и некоторые моменты по возвращению значений а то там в первоисточнике типа знак инверсии чтоли стоял на проверку.
Procedure CALLBACK_TimerRoutine(lpParam, TimerOrWaitFired)
If (lpParam = NULL)
;printf("TimerRoutine lpParam is NULL\n");
Debug "TimerRoutine lpParam is NULL\n"
Else
;// lpParam points To the argument; in this case it is an int
;printf("Timer routine called. Parameter is %d.\n", *(int*)lpParam);
Debug "Timer routine called. Parameter is %d.\n ," +Str(lpParam)
If(TimerOrWaitFired)
;printf("The wait timed out.\n");
Debug "The wait timed out.\n"
Else
;rintf("The wait event was signaled.\n");
Debug "The wait event was signaled.\n"
EndIf
EndIf
SetEvent_(gDoneEvent);
EndProcedure
Procedure.i main()
Protected hTimer = #Null;
Protected hTimerQueue = #Null;
Protected arg.i = 123;
;// Use an event object To track the TimerRoutine execution
gDoneEvent = CreateEvent_(#Null, #True, #False, #Null);
If (#Null = gDoneEvent)
;printf("CreateEvent failed (%d)\n", GetLastError());
Debug "CreateEvent failed (%d)\n "+Str(GetLastError_())
ProcedureReturn 1;
EndIf
;// Create the timer queue.
; hTimerQueue = CreateTimerQueue_();нет штатно функции
If (#Null = hTimerQueue)
;printf("CreateTimerQueue failed (%d)\n", GetLastError());
Debug "CreateEvent failed (%d)\n "+Str(GetLastError_())
ProcedureReturn 2;
EndIf
;// Set a timer To call the timer routine in 10 seconds.
;If CreateTimerQueueTimer_( @hTimer, hTimerQueue, CALLBACK_TimerRoutine, @arg , 10000, 0, 0);;нет штатно функции
;printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
Debug "CreateEvent failed (%d)\n "+Str(GetLastError_())
ProcedureReturn 3;
;EndIf
;// TODO: Do other useful work here
;printf("Call timer routine in 10 seconds...\n");
Debug "Call timer routine in 10 seconds...\n"
;// Wait For the timer-queue thread To complete using an event
;// object. The thread will signal the event at that time.
If (WaitForSingleObject_(gDoneEvent, INFINITE) <> #WAIT_OBJECT_0)
;printf("WaitForSingleObject failed (%d)\n", GetLastError());
Debug "WaitForSingleObject failed (%d)\n "+ Str(GetLastError_())
CloseHandle_(gDoneEvent);
EndIf
;/ Delete all timers in the timer queue.
If DeleteTimerQueue_(hTimerQueue)
;printf("DeleteTimerQueue failed (%d)\n", GetLastError());
Debug "DeleteTimerQueue failed (%d)\n "+ Str(GetLastError_())
EndIf
ProcedureReturn 0;
EndProcedure
Отредактировано Sergeihik (06.09.2021 20:56:58)
Поделиться2307.09.2021 07:03:49
нужно использовать CreateTimerQueue
какой то код попался и перевёл на скору руку но оказалось нет таких в пурике функций
Import "" CreateTimerQueue() CreateTimerQueueTimer(a,b,c,d,e,f,g) EndImport Global cc Procedure Timer(parameter.i, b.b) cc+1 EndProcedure tq = createtimerqueue() CreateTimerQueueTimer(@thandle.i, tq, @Timer(), 0, 0, 1, $80) Delay(10000) Debug cc
Ещё
Import "kernel32.lib"
CreateTimerQueue()
DeleteTimerQueueTimer(hTimerQueue, hTimer, completionEvent)
DeleteTimerQueueEx(hTimerQueue, completionEvent)
ChangeTimerQueueTimer (hTimerQueue, hTimer, dueTime, period)
CreateTimerQueueTimer(hTimer, hTimerQueue, timerCallback, param, dueTime, period, flags)
EndImport
Global timer_Q1, timer_Q2, timer_Q3,tm.l,tx.l
Procedure timerProc_Q(param.i, timer.i)
SetGadgetText(1, Str(tm)+" "+"Timer high priority")
tm+1
EndProcedure
wFlags = #PB_Window_ScreenCentered | #PB_Window_SystemMenu
OpenWindow(0, #PB_Any, #PB_Any, 280, 120, "Windows Queue Timer", wFlags)
TextGadget(1, 50, 20, 200, 30, "Timer 1: ")
TextGadget(2, 50, 50, 200, 30, "Timer 2: ")
timerQueue = CreateTimerQueue()
CreateTimerQueueTimer(@timer_Q1, timerQueue, @timerProc_Q(), 1, 0, 100, 0)
AddWindowTimer(0, 123, 100)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
appQuit = 1
Case #PB_Event_Timer
SetGadgetText(2, Str(tx)+" "+"Timer low priority")
tx+1
EndSelect
Until appQuit = 1
DeleteTimerQueueEx(timerQueue, 0)Поделиться2407.09.2021 19:08:45
Уже видно что он работает как бы из собственного потока,когда будешь перетаскивать окно его основной поток притормозится и таймер соответственно пуриковский ну или тот что работает через сообщения окну замрёт а этот работает.
вобщем надо пробывать встроить в код и посмотреть что получится,код потом опубликую как попробую.
Поделиться2508.09.2021 12:27:27
потока,когда будешь перетаскивать окно его основной поток притормозится и таймер соответственно пуриковский ну или тот что работает через сообщения окну замрёт а этот работает.
Перетащи окно.
Procedure Timer()
Static Value
Value = (Value + 5) % 100
SetGadgetState(0, Value)
EndProcedure
If OpenWindow(0, 0, 0, 400, 100, "Timer Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ProgressBarGadget(0, 10, 10, 380, 20, 0, 100)
AddWindowTimer(0, 123, 250)
BindEvent(#PB_Event_Timer, @Timer(), 0, 123)
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIfПоделиться2611.09.2021 00:39:30
Перетащи окно.
Да и тащить то ненужно,достаточно мышкой пощёлкать и видно как сбивается он притормаживая.
Поделиться2717.09.2021 20:30:34
С временем проигрывания не зря писал что вникаю потихоньку(да ещё этот формат записи путает),вообщем слышно было что некоторые промежутки в проигрывании композиции пролетают.
И неправильный был участок кода определения времени событияэ
If PeekA(*sobytie) & $80;время события по дельте времени в одном байте
delta_kolihestvoBait=2
zikl:
*sobytie+1
If PeekA(*sobytie) & $80
delta_kolihestvoBait+1
Goto zikl
EndIf
*sobytie+1
Else;иначе в байтах переменной длинны
*sobytie+1
delta_kolihestvoBait=1
EndIf
Debug "delta_kolihestvoBait "+Str(delta_kolihestvoBait)
If delta_kolihestvoBait=1
delta_time_sobytie=PeekA(*sobytie-1)
ElseIf delta_kolihestvoBait=2
delta_time_sobytie=PeekW(*sobytie-2)
!ror word [p.v_delta_time_sobytie],8
EndIf
Debug "delta_time_sobytie "+Str(delta_time_sobytie)
изменил на это
delta_time_sobytie=0
;Debug r
cikl8:
If *Sobytie\bait1 & $80;есле он не один
delta_time_sobytie|(*Sobytie\bait1 & $7F)
delta_time_sobytie<<7;сдвинуть на семь бтов под следующий байт
*Sobytie+1
Goto cikl8
Else
delta_time_sobytie|*Sobytie\bait1
*Sobytie+1
EndIf
Debug "delta_time_sobytie "+Str(delta_time_sobytie)
А ну да выкинул функцию peek() и перешёл на структуру с объявлением Protected *sobytie.Sobytie
Structure Sobytie bait1.a bait2.a bait3.a bait4.a EndStructure
Вобщем код позже.
Хочу ещё попробывать несколько треков ну типа синхронно проиграть по событию тика метронома и просто с задержкой по типу delay() и посмотреть
Так образно накидал метроном
Import "kernel32.lib"
CreateTimerQueue()
DeleteTimerQueueTimer(hTimerQueue, hTimer, completionEvent)
DeleteTimerQueueEx(hTimerQueue, completionEvent)
ChangeTimerQueueTimer (hTimerQueue, hTimer, dueTime, period)
CreateTimerQueueTimer(hTimer, hTimerQueue, timerCallback, param, dueTime, period, flags)
EndImport
Global timer_Q1, timer_Q2
Procedure timerProc_Q1(param.i, timer.i)
Static tm
SetGadgetText(1, Str(tm)+" "+"Timer high priority")
tm+1
Beep_(900,100)
EndProcedure
Procedure timerProc_Q2(param.i, timer.i)
Static tm2
SetGadgetText(2, Str(tm2)+" "+"Timer high priority")
tm2+1
Beep_(900,100)
EndProcedure
OpenWindow(0, #PB_Any, #PB_Any, 280, 120, "Метроном", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
TextGadget(1, 50, 20, 200, 30, "Timer 1: ")
TextGadget(2, 50, 50, 200, 30, "Timer 2: ")
Global bmp.i=150
bmp=(60000/bmp)
Debug bmp
timerQueue = CreateTimerQueue()
CreateTimerQueueTimer(@timer_Q1, timerQueue, @timerProc_Q1(), 0, 0, bmp, $80|$100)
CreateTimerQueueTimer(@timer_Q2, timerQueue, @timerProc_Q2(), 0, 1000, bmp, $80|$100)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
appQuit = 1
DeleteTimerQueueEx(timerQueue, 0)
EndSelect
Until appQuit = 1
Structure Sobytie
bait1.a
bait2.a
bait3.a
bait4.a
EndStructure
*Sobytie.Sobytie
Global r.i
*mem=AllocateMemory(100)
*Sobytie.Sobytie=*mem
PokeA(*Sobytie,128)
PokeA(*Sobytie+1,129)
PokeA(*Sobytie+2,0)
r=0
Debug r
cikl:
If *Sobytie\bait1 & $80;есле он не один
r|(*Sobytie\bait1 & $7F)
r<<7;сдвинуть на семь бтов под следующий байт
*Sobytie+1
;; r|*Sobytie\bait1;добавляем второй байт
Debug r
Goto cikl
Else
r|*Sobytie\bait1
*Sobytie+1
EndIf
Debug r
FreeMemory(*mem)
Отредактировано Sergeihik (17.09.2021 20:43:08)
Поделиться2819.09.2021 13:14:37
попробОвать
Поделиться2922.09.2021 00:23:54
Пробуй,только без отладчика что то не компилится у меня(вобщем компилится но не работает).
Ну и теперь когда много треков (формат 1),то бывают задержки композиции.
Structure hMidiOut;тупо для ссылки на процедуры
hMidiOut.i
EndStructure
;
Structure Sobytie
bait1.a
bait2.a
bait3.a
bait4.a
EndStructure
;
Structure Mtrk
Mtrk.i;заголовок блока трека
Dlina_treka.l;блока mtrk за этими 8 байт заголовка
EndStructure
Structure Midi_zagolovok
MThd.i;заголовок
Dlina_zapisi.i;длинна последующая после этих 8 байтов
Format_midi.w;3 формата 0=данные записаны на одном треке(все сообщения со всех MIDI-каналов в одном треке),1-в нескольких отдельных,2-несколько независимых
NumTrek.w; количество записей MTRK, количество блоков (треков) в файле,(первый карта темпа)
PPQN.w;временные тики
EndStructure
Global hMidiOut.i
Global midiport.i
Procedure Error(funkciy$,ohibka.i)
Select ohibka
Case #MIXERR_BASE
MessageRequester(funkciy$,"Минимальное значение кода ошибки микшера")
Case #MIXERR_INVALLINE
MessageRequester(funkciy$,"Недопустимый индекс/идентификатор линии")
Case #MIXERR_INVALCONTROL
MessageRequester(funkciy$,"Недопустимый индекс/идентификатор элемента управления")
Case #MIXERR_INVALVALUE
MessageRequester(funkciy$,"Недопустимое значение элемента управления")
Case #MIXERR_LASTERROR
MessageRequester(funkciy$,"Максимальное значение кода ошибки микшера")
Case #MMSYSERR_ALLOCATED
MessageRequester(funkciy$,"Устройство занято другим приложением")
Case #MMSYSERR_BADDEVICEID
MessageRequester(funkciy$,"Недопустимый номер устройства")
Case #MMSYSERR_NOTENABLED
MessageRequester(funkciy$,"Драйвер не активизирован")
Case #MMSYSERR_INVALFLAG
MessageRequester(funkciy$,"Один или несколько флагов недействительны.")
Case #MMSYSERR_INVALHANDLE
MessageRequester(funkciy$,"Недопустимый дискриптор открытого устройства")
Case #MMSYSERR_INVALPARAM
MessageRequester(funkciy$,"Один или несколько параметров недействительны.")
Case #MMSYSERR_NODRIVER
MessageRequester(funkciy$,"Драйвер отсутствует")
Case #MMSYSERR_NOMEM
MessageRequester(funkciy$,"Недостаточно памяти для выделения")
Case #MMSYSERR_NOTSUPPORTED
MessageRequester(funkciy$,"Запрошенная функция не поддерживается")
Case #MMSYSERR_HANDLEBUSY
MessageRequester(funkciy$,"Над ключом выполняется операция от другой задачи (thread)")
Case #MMSYSERR_INVALIDALIAS ;13
Case 14;#MMSYSERR_BADDB ;14
Case 15;#MMSYSERR_KEYNOTFOUND ;15
Case 16;#MMSYSERR_READERROR ;16
Case 17;#MMSYSERR_WRITEERROR; 17
Case 18;#MMSYSERR_DELETEERROR ;18
Case 19;#MMSYSERR_VALNOTFOUND ;19
Case 20;#MMSYSERR_NODRIVERCB
;MessageRequester(funkciy$,"Драйвер не выполнил уведомления (callback)")
Case #MMSYSERR_BADERRNUM
MessageRequester(funkciy$,"Код ошибки вне допустимого диапазона")
Case #MMSYSERR_ERROR
MessageRequester(funkciy$,"Неопределенная ошибка")
EndSelect
EndProcedure
Procedure.i midiinit(Konstanta.i)
Protected midi.MIDIOUTCAPS
Protected devnum
#MOD_MIDIPORT =1;Аппаратный порт MIDI.
#MOD_SYNTH =2;Синтезатор
#MOD_SQSYNTH=3;Синтезатор прямоугольных импульсов.
#MOD_FMSYNTH=4;FM-синтезатор.
#MOD_MAPPER =5;Microsoft MIDI маппер.
#MOD_WAVETABLE=6;Аппаратный волновой синтезатор.
#MOD_SWSYNTH=7 ;Программный синтезатор
If midiOutGetNumDevs_();извлекает количество MIDI-устройств вывода,0=нет устройств
For devnum=0 To 7
If midiOutGetDevCaps_(devnum,@midi,SizeOf(MIDIOUTCAPS))=0
Debug midi\wTechnology;что есть
If midi\wTechnology=Konstanta;#MOD_SWSYNTH
Debug PeekS(@midi\szPname,-1,#PB_Unicode);Название продукта в строке с нулевым символом в конце.
Debug midi\wVoices;количество голосов
Debug midi\wNotes ;количество одновременных нот, которые могут быть воспроизведены
Debug midi\wChannelMask;Портовые устройства, которые передают по всем каналам, устанавливают этот элемент в 0xFFFF.
Debug midi\dwSupport;Дополнительный функционал, поддерживаемый устройством(MIDICAPS_VOLUME=1 Поддерживает регулировку громкости.)
ProcedureReturn devnum
EndIf
EndIf
Next
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i midiOutOpen(midiport.i,*hMidiOut.hMidiOut,flagi.i,dwCallback.i=0,CallbackInstance.i=0);открывает выходное MIDI-устройство
Protected result.i
result=midiOutOpen_(*hMidiOut.hMidiOut,midiport,dwCallback,CallbackInstance,flagi)
If result=MMSYSERR_NOERROR
ProcedureReturn 1
Else
Error("Error midiOutOpen()",result)
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i midiOutClose(*hMidiOut);получаем дискриптор устройства
Protected MidiOut.i
!mov dword eax,[p.p_hMidiOut]
!mov dword eax,[eax]
!mov dword [p.v_MidiOut],eax
If midiOutClose_(MidiOut)=#MMSYSERR_NOERROR
!mov dword eax,[p.p_hMidiOut]
!mov dword [eax],0
ProcedureReturn 1
Else
MessageRequester("Error midiOutClose()","INVALIDE_HANDLE hMidiOut")
ProcedureReturn 0
EndIf
EndProcedure
Procedure Revers_i(*adres)
!mov dword eax,[p.p_adres]
!ror word [eax],8
!ror dword [eax],16
!ror word [eax],8
EndProcedure
Procedure Revers_w(*adres)
!mov dword eax,[p.p_adres]
!ror word [eax],8
EndProcedure
Procedure MidiOutMesage(hMidi,iStatus,iData1,iData2)
Protected dwMessage.i
dwMessage = iStatus | (iData1 << 8 ) | (iData2 << 16)
ProcedureReturn midiOutShortMsg_(hMidi, dwMessage)
EndProcedure
Procedure Open_midi()
Protected OpenFile.s
Protected light.l
Protected *Midi_zagolovok.Midi_zagolovok
Protected *Mtrk.Mtrk
Protected kolihestvoMtrk.l
Protected dlinaMtrk.i
Protected PPQN.w
Protected *mem
Protected *sobytie.sobytie
Protected delta_time_sobytie.i
Protected temp.i
Protected baitsobytiy.a
OpenFile.s=OpenFileRequester("Открыть файл", "", "*.midi|*.midi|All Files|*.*", 0);диалог
If OpenFile<>"";если имя файла 1 и более символа
If ReadFile(0, OpenFile)
light=Lof(0)
If light>0
*mem=AllocateMemory(light)
Debug *mem
If *mem>0
Debug ReadData(0,*mem,light)
CloseFile(0)
;============================== обработка памяти
*Midi_zagolovok=*mem
Debug PeekS(@*Midi_zagolovok\MThd,4,#PB_Ascii)
Revers_i(@*Midi_zagolovok\Dlina_zapisi)
Debug Str(PeekI(@*Midi_zagolovok\Dlina_zapisi))
;
Revers_w(@*Midi_zagolovok\Format_midi)
Debug Str(PeekW(@*Midi_zagolovok\Format_midi))
;
Revers_w(@*Midi_zagolovok\NumTrek)
kolihestvoMtrk=PeekW(@*Midi_zagolovok\NumTrek)
Debug "kolihestvoMtrk(Треков) "+Str(kolihestvoMtrk)
;{;PPQN
PPQN=*Midi_zagolovok\PPQN
Debug "PPQN "+Str(PPQN)
PPQN=((PPQN>>8)& $FF) |(PPQN<<8);реверс
If PPQN & $8000;Если старший бит установлен в единицу, то используется абсолютный способ иначе музыкальный а оставшиеся 15 бит содержат PPQN (до 32767)
PPQN>>8
PPQN & $7F;обнулить включая старший бит =количество тиков в четверти(допустим 96)
EndIf
Debug "PPQN 2 "+Str(PPQN)
;};
;
If PeekS(@*Midi_zagolovok\MThd,4,#PB_Ascii)="MThd"
Select PeekW(@*Midi_zagolovok\Format_midi);format
Case 0,1
;Case 1
;{;format 0,1
*sobytie.sobytie=*mem
*sobytie+14
cikl3:
If kolihestvoMtrk>0
*Mtrk=*sobytie
Debug PeekS(@*Mtrk\Mtrk,4,#PB_Ascii)
If PeekS(@*Mtrk\Mtrk,4,#PB_Ascii)="MTrk"
Revers_i(@*Mtrk\Dlina_treka);могут быть сообщения разной длинны
Debug "Dlina_treka "+Str(*Mtrk\Dlina_treka)
dlinaMtrk=*Mtrk\Dlina_treka
If dlinaMtrk>0
*sobytie+8;*Mtrk+8
cikl:
;;следущий байт за заголовком mtrk (пошли события)
;{;сначала указано время события
delta_time_sobytie=0
cikl8:
If *Sobytie\bait1 & $80;есле он не один
delta_time_sobytie|(*Sobytie\bait1 & $7F)
delta_time_sobytie<<7;сдвинуть на семь бтов под следующий байт
*Sobytie+1
Goto cikl8
Else
delta_time_sobytie|*Sobytie\bait1
*Sobytie+1
EndIf
Debug "delta_time_sobytie "+Str(delta_time_sobytie)
;};
;=========Команды события========
baitsobytiy=*sobytie\bait1;статус байт события
cikl5:
Debug "baitsobytiy "+Hex(baitsobytiy)
If baitsobytiy=$F0;{;sysEx-сообщение
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=>$90 And baitsobytiy<=$9F;{;nota on
delta_time_sobytie*temp/1000
Debug delta_time_sobytie
Delay(delta_time_sobytie)
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,*sobytie\bait3)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$80 And baitsobytiy<=$8F;{;nota off
delta_time_sobytie*temp/1000
Debug delta_time_sobytie
Delay(delta_time_sobytie)
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,*sobytie\bait3)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$C0 And baitsobytiy<=$CF;{;Событие SetInstrument(установка инструмента в каналы)
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,0);следущий байт собственно номер инструмента
Debug Hex(PeekA(*sobytie+1))
*sobytie+2
Goto cikl
;};
ElseIf baitsobytiy=>$A0 And baitsobytiy<=$AF;{;
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,*sobytie\bait3)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$B0 And baitsobytiy<=$BF;{;Специальные канальные сообщения,Задаются контpоллеpами 120..127 и упpавляют обpаботкой сообщений в каналах:
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,*sobytie\bait3)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=>$D0 And baitsobytiy<=$DF;{;манипуляция после нажатия клавиши(давление в канале)
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,0)
*sobytie+2
Goto cikl
;};
ElseIf baitsobytiy=>$E0 And baitsobytiy<=$EF;{;Pitch Bend Change (смена значения чувствительности для каналов Pitch Bend)изменение высоты звука
MidiOutMesage(hMidiOut,*sobytie\bait1,*sobytie\bait2,*sobytie\bait3)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=$FF;{;мета события (17-ть мета событий-?)
*sobytie+1
baitsobytiy=*sobytie\bait1;
Debug "Мета событие "+Hex(baitsobytiy)
If baitsobytiy=0;{;Sequence Number
;Это необязательное мета-событие имеет структуру, показанную на рис. 20. Оно задает номер секвенции (паттерна), на который можно
;ссылаться в дальнейшем при помощи сообщений MIDI Cueing. В таком виде это мета-событие имеет смысл только для формата 2, поскольку
;в файлах формата 0 и 1 есть только одна секвенция (то есть целая композиция). Событие должно располагаться в начале трека, перед
;любым событием с ненулевым дельта-временем, и перед любым другим MIDI-событием. Если номер секвенции опущен, то считается
;что секвенции (паттерны) следуют в порядке расположения блоков трека в файле. Если необходимо сохранить несколько многотрековых
;композиций в виде группы файлов формата 0 или 1, то событие Sequence Number может использоваться в качестве номера файла.
*sobytie+4
Goto cikl
;};
ElseIf baitsobytiy=1;{;Text Event
Debug "fffffffff111111111_Text Event"
Debug PeekA(*sobytie+1)
Debug PeekS(*sobytie+2,PeekA(*sobytie+1),#PB_Ascii)
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=2;{;Содержит заметку об авторских правах.
;Заметка должна содержать символы "(", "C" и ")", год и владельца авторских прав. Если в одном файле содержатся несколько произведений, все заметки об авторских правах должны быть размещены в начале файла. Заметка должна быть первым событием в первом блоке трека в момент времени 0.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=3;{;Содержит название произведения
;если находится в файле формата 0 или в первом блоке трека в файле формата 1), в остальных случаях — название трека.
*sobytie+1
Debug PeekA(*sobytie);следующая длина в байтах (название произведения)
Debug PeekS(*sobytie+1,PeekA(*sobytie),#PB_Ascii);
*sobytie+PeekA(*sobytie)+1
Goto cikl;смотрим следующие событие
;};
ElseIf baitsobytiy=4;{;Содержит название инструмента, которым должен исполняться трек.
Debug "инструмент "+PeekS(*sobytie+2,PeekA(*sobytie+1),#PB_Ascii)
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=5;{;Lyric/Display Meta Event.
;Задает слова песни, которые должны быть исполнены в указанное время. Обычно каждый слог представлен отдельным событием Lyric,
;то есть для каждого слога четко задано время исполнения. В 1997 году организация MMA расширила это событие, добавив команды
;форматирования при выводе текста на экран, поддержку многобайтовой кодировки символов и Unicode, а также информацию о произведении
;(название, композитор, исполнитель). Расширенное мета-событие Lyric предложено называть Lyric/Display Meta Event.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=6;{;Marker
;Событие располагается обычно на первом блоке трека в файле формата 1 (или на единственном треке формата 0).
;Определяет позицию внутри произведения и одновременно задает ее имя.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=7;{;Задает точку привязки партитуры
;;Задает точку привязки партитуры к моменту кино-, видео- или сценического действия и одновременно описание момента
;(например, "Машина въехала в дерево", "Герой получил пощечину").
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=8;{;Program Name
;Это мета-событие служит для визуальной ориентировки и информирования пользователя об используемом имени пэтча на данном канале.
;Непосредственно за этим событием должны следовать события Bank Select и Program Change, посредством которым реально выбирается
;пэтч. Если на протяжении звучания трека на том же MIDI-канале изменяется пэтч, событие
;Program Name может встречаться перед каждым таким изменением.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;}
ElseIf baitsobytiy=9;{;Это мета-событие позволяет в одном MIDI-файле задать несколько устройств воспроизведения (тон-генераторов)
;то есть реализовать более 16 MIDI-каналов.Например, в аранжировке могут быть задействованы два тон-генератора
;первый подключен к порту "MIDI Out 3" интерфейса, второй — к порту "MIDI Out 4"
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
ElseIf baitsobytiy=$20;{;MIDI Channel Prefix
;Поскольку SysEx-события и мета-события не содержат в статус-байте номер MIDI-канала, нужен способ привязки этих событий
;к MIDI-каналу.Событие MIDI Channel Prefix содержит номер MIDI-канала,с которым ассоциируются все последующие SysEx- и мета-события
;Канал, заданный таким образом, остается действительным до следующего нормального MIDI-события (которое содержит номер канала)
;или до следующего мета-события MIDI Channel Prefix.
;Если каждый трек в секвенсоре соответствует одному MIDI-каналу, то при записи аранжировки в формате 0 это мета-событие помогае
;т сохранить связь мета-событий с конкретным треком. Подобная возможность предусмотрена и в формате файлов Yamaha ESEQ.
Debug "префикс канала "+PeekA(*sobytie+2)
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=$21;{;MIDI Port
;Это необязательное событие, которое обычно происходит в начале MTrk (т. Е. Перед любым
;ненулевое дельта-время и перед любыми событиями midi) указывает, из какого порта MIDI (т. е.
;buss) MIDI-события в MTrk go. Байт данных pp, это номер порта, где 0
;будет первой шиной MIDI в системе.
;Спецификация MIDI имеет ограничение в 16 MIDI-каналов на вход / выход MIDI (т. Е. Порт, шина,
;jack, или любую другую терминологию, которую вы используете для описания оборудования для одного MIDI-входа /
*sobytie+3
Goto cikl
;};
ElseIf baitsobytiy=$2F;{;End of Track
;Это обязательное мета-событие (рис. 23) указывает момент окончания трека. Должно быть последним событием внутри блока трека.
;Точный момент окончания трека необходим секвенсорам для возможности воспроизведения трека в цикле или стыковки его с другим треком
kolihestvoMtrk-1
*sobytie+2
;Debug "kolihestvoMtrk "+Str(kolihestvoMtrk)
Goto cikl3
;};
ElseIf baitsobytiy=$51;{;Set Tempo,
;Задает текущий темп в необычном измерении — микросекунды на четверть. Представление темпа в виде "время на четверть"
;вместо "четверть за время" позволяет осуществить точную долговременную синхронизацию при работе по протоколу MTC или SMPTE.
;Так, если число тиков 3240, темп 120 BPM (500000 мкс на четверть), 96 тиков в четверти (96 PPQN), время в миллисекундах
;равно 3240 x (500000/96(PPQN)) / 1000 = 16875 мкс (или 16,875 млс).
temp=PeekA(*sobytie+4)|(PeekA(*sobytie+3)<<8)|(PeekA(*sobytie+2)<<16)
;temp=*sobytie\bait4|(*sobytie\bait3<<8)|(*sobytie\bait2<<16)
Debug temp
;temp=60000000/temp;BMP
;;temp=(60000/temp); в миллисекундах
temp/PPQN;(PPQN)
Debug temp
*sobytie+5;bait peremennogo razmera i dannye
Goto cikl
;}
ElseIf baitsobytiy=$54;{;SMPTE Offset
;Это необязательное мета-событие задает время SMPTE, с которого начинается трек. Событие должно располагаться в начале трека
;перед любым другим событием с ненулевым дельта-временем, и перед любым MIDI-событием. В файле формата 1 смещение SMPTE должно
;храниться с картой темпа на первом треке. Поле ff содержит сотые доли кадра, даже в том случае, если в блоке заголовка определено
;другое количество тиков на кадр.
*sobytie+7
Goto cikl
;};
ElseIf baitsobytiy=$58;{;PPQN Signature,Событие задает музыкальный размер,
*sobytie+6
Goto cikl
;};
ElseIf baitsobytiy=$59;{;Key Signature
;Событие задает текущую тональность (точнее, ладотональность — высоту и наклонение лада, мажор/минор)
*sobytie+4
Goto cikl
;};
ElseIf baitsobytiy=$7F;{;Sequencer-Specific Meta-Event
;применяется аналогично системным эксклюзивным сообщениями в протоколе MIDI. То есть, позволяет записывать в MIDI-файл информацию
;специфичную для конкретного секвенсора. Длина события выражается переменным способом. Первый байт данных (или три байта)
;содержат ID производителя. Остальной формат события определяется конкретным производителем под конкретную программу или семейство
;программ.
*sobytie+PeekA(*sobytie+1)+2
Goto cikl
;};
EndIf
;};
EndIf
EndIf
EndIf
EndIf
;};
Case 2;format 2
EndSelect
EndIf
;==============================
Debug *mem
FreeMemory(*mem)
EndIf
EndIf
Else
MessageRequester("Открытие файла","Не удалось открыть файл!",#MB_OK | #MB_ICONERROR)
EndIf
EndIf
EndProcedure
OpenWindow(0,0,0,100,180,"",#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
ButtonGadget(2,10,5,92,20,"Open midi")
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case 2
midiport=midiinit(#MOD_SWSYNTH)
If midiport>-1;есле есть программный синтезатор
If midiOutOpen(midiport,@hMidiOut,#CALLBACK_NULL)
Open_midi()
midiOutClose(@hMidiOut)
EndIf
EndIf
EndSelect
EndSelect
ForEver
End
Отредактировано Sergeihik (22.09.2021 00:26:06)
Поделиться3022.09.2021 01:15:52
Пробуй,только без отладчика что то не компилится у меня(вобщем компилится но не работает).
Debug ReadData(0,*mem,light)