purebasic.info

PureBasic forum
Текущее время: Ср сен 19, 2018 4:38 am

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 41 ]  На страницу Пред.  1, 2, 3  След.
Автор Сообщение
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Чт июл 30, 2015 1:23 pm 
Не в сети
профессор

Зарегистрирован: Вт мар 24, 2009 11:54 am
Сообщений: 357
Благодарил (а): 14 раз.
Поблагодарили: 18 раз.
Пункты репутации: 19
SereZa писал(а):
момент номер два: в одном проекте лежит два файла:
patch_20.ins и patch_20.raw - этот patch_20.raw видимо является инструментом для миди. можно ли его как-то подключить к миди и заставить играть через этот инструмент?


если можно по подробнее о размере файлов


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Чт июл 30, 2015 2:42 pm 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
приложил.


Вложения:
rawfile.rar [213 байт]
Скачиваний: 103
Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Чт июл 30, 2015 3:07 pm 
Не в сети
профессор

Зарегистрирован: Вт мар 24, 2009 11:54 am
Сообщений: 357
Благодарил (а): 14 раз.
Поблагодарили: 18 раз.
Пункты репутации: 19
судя по размеру там ничего нет. скорее всего это просто доп файлы

посмотри формат SF2 может тебе это поможет.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Пт июл 31, 2015 6:54 am 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
тут опять закавыка с этим миди... насколько я помню при выставлении 10 дорожки в миди - она работает как барабаны. независимо от выбранного инструмента. соответственно при запуске ноты в 10 канале должны быть какие-то барабаны, однако нифига :) как правильно выставить этот 10 канал? упс... пока писал додумался проверить 9 канал... и забарабанило :) выходит миди в PB считает с 0, а не с 1? кхм...


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Пт июл 31, 2015 10:28 am 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
а как можно громкость каждого канала регулировать?

нашлось :)
Procedure MIDIVolume(Channel,Volume)
Debug midiOutShortMsg_(hMidiOut,$B0 | Channel | $700 | Volume << 16 )
EndProcedure


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Сб авг 01, 2015 7:36 pm 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
у буржуев нашелся код для миди:
"lib_midi.pb"
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
EnableExplicit
 
;> ---------------------- <
;- MidiParser : Constants
;> ---------------------- <
 
#MIDI_Chunk_Header = 'dhTM' ;"MThd"
#MIDI_Chunk_Track  = 'krTM' ;"MTrk"
 
Enumeration ;MIDI track types
      #MIDI_Track_Single
      #MIDI_Track_Synchronous
      #MIDI_Track_Asynchronous
EndEnumeration
 
;> ----------------------- <
;- MidiParser : Structures
;> ----------------------- <
 
Structure MIDICHUNK
      dwType.l
      dwSize.l ;remaining size
EndStructure
 
Structure MIDIHEADER
      wTrack.w ;track type
      wCount.w ;number of tracks
      wDelta.w ;delta time
EndStructure
Macro LoNibble(x)
      (x & $0F)
EndMacro
 
Macro HiNibble(x)
      (x >> 4)
EndMacro
 
Structure Bytes
      b.b[4]
EndStructure
 
;> ---------------------------------- <
;- MidiParser : Variable-Length Value
;> ---------------------------------- <
 
#MIDI_VarLen_Max   = $0FFFFFFF ;4 reserved Bytes
#MIDI_VarLen_Error = $FFFFFFFF ;impossible VarLen or Num value
 
Procedure.l NumToVarLen(Num.l)
      Protected VarLen.l, i.l
      Protected *VarLen.Bytes
     
      If Num & ~#MIDI_VarLen_Max
           
            VarLen = #MIDI_VarLen_Error
           
      Else
            *VarLen = @VarLen
           
            *VarLen\b[0] = (Num >>  0) & $7F
            *VarLen\b[1] = (Num >>  7) & $7F
            *VarLen\b[2] = (Num >> 14) & $7F
            *VarLen\b[3] = (Num >> 21) & $7F
           
            i = 3
           
            While i > 0 And Not *VarLen\b[i]
                  i - 1
            Wend
           
            While i > 0
                  *VarLen\b[i] | $80
                  i - 1
            Wend
      EndIf
     
      ProcedureReturn VarLen
EndProcedure
 
Procedure.l VarLenToNum(VarLen.l)
      Protected Num.l, i.l
      Protected *VarLen.Bytes
     
      *VarLen = @VarLen
     
      Num | (*VarLen\b[0] & $7F) <<  0
      Num | (*VarLen\b[1] & $7F) <<  7
      Num | (*VarLen\b[2] & $7F) << 14
      Num | (*VarLen\b[3] & $7F) << 21
     
      If VarLen <> NumToVarLen(Num)
            Num = #MIDI_VarLen_Error
      EndIf
     
      ProcedureReturn Num
EndProcedure
 
Procedure.l WriteVarLen(File.l, Num.l)
      Protected Write.l, VarLen.l, i.l
      Protected *VarLen.Bytes
     
      VarLen = NumToVarLen(Num)
     
      If IsFile(File) And VarLen <> #MIDI_VarLen_Error
            *VarLen = @VarLen
           
            i = 3
           
            While Not *VarLen\b[i]
                  i - 1
            Wend
           
            While i >= 0
                  Write + WriteByte(File, *VarLen\b[i])
                  i - 1
            Wend
      EndIf
     
      ProcedureReturn Write
EndProcedure
 
Procedure.l ReadVarLen(File.l)
      Protected VarLen.l, len.l
     
      If IsFile(File)
            Repeat
                  VarLen = (VarLen << 8) | (ReadByte(File) & $FF)
                  len + 1
            Until Not VarLen & $80
           
            If len > 4
                  VarLen = #MIDI_VarLen_Error
            EndIf
      Else
            VarLen = #MIDI_VarLen_Error
      EndIf
     
      ProcedureReturn VarLenToNum(VarLen)
EndProcedure
 
Procedure.l VarLenSize(Value.l, IsVarLen.l = #False)
      Protected Size.l
     
      If IsVarLen
            Value = VarLenToNum(Value)
      EndIf
     
      If Value < 0
            Size = #MIDI_VarLen_Error
      ElseIf Value < (1 <<  7)
            Size = 1
      ElseIf Value < (1 << 14)
            Size = 2
      ElseIf Value < (1 << 21)
            Size = 3
      ElseIf Value < (1 << 28)
            Size = 4
      Else
            Size = #MIDI_VarLen_Error
      EndIf
     
      ProcedureReturn Size
EndProcedure
 
;> ---------------------- <
;- MidiParser : BigEndian
;> ---------------------- <
 
ProcedureDLL.w PeekBigEndianW(*MemoryBuffer)
      !MOV   eax, dword [p.p_MemoryBuffer]
      !MOV    ax,  word [eax]
      !BSWAP eax
      !SHR  eax, 16
      ProcedureReturn
EndProcedure
 
ProcedureDLL.l PeekBigEndianL(*MemoryBuffer)
      !MOV   eax, dword [p.p_MemoryBuffer]
      !MOV   eax, dword [eax]
      !BSWAP eax
      ProcedureReturn
EndProcedure
 
ProcedureDLL.q PeekBigEndianQ(*MemoryBuffer)
      !MOV   eax, dword [p.p_MemoryBuffer]
      !MOV   edx, dword [eax+0]
      !MOV   eax, dword [eax+4]
      !BSWAP eax
      !BSWAP edx
      ProcedureReturn
EndProcedure
 
ProcedureDLL.q PeekBigEndianN(*MemoryBuffer.Bytes, Size.l)
      Protected Result.q, i.l
     
      While i < Size
            Result << 8
            Result | (*MemoryBuffer\b[i] & $FF)
            i + 1
      Wend
     
      ProcedureReturn Result
EndProcedure
 
ProcedureDLL.w ReadBigEndianW(File)
      ReadWord(File)
      !BSWAP eax
      !SHR  eax, 16
      ProcedureReturn
EndProcedure
 
ProcedureDLL.l ReadBigEndianL(File)
      ReadLong(File)
      !BSWAP eax
      ProcedureReturn
EndProcedure
 
ProcedureDLL.q ReadBigEndianQ(File)
      ReadQuad(File)
      !XOR   eax, edx
      !XOR   edx, eax
      !XOR   eax, edx
      !BSWAP eax
      !BSWAP edx
      ProcedureReturn
EndProcedure
 
;> --------------------------- <
;- MidiParser : Event handlers
;> --------------------------- <
 
Enumeration ;Event types
      #MidiParser_Event_Header  ;header chunk handler
      #MidiParser_Event_Track   ;track chunk handler
      #MidiParser_Event_Command ;channel event handler
      #MidiParser_Event_SysEx   ;system exclusive handler
      #MidiParser_Event_System  ;system event handler
      #MidiParser_Event_Meta    ;meta event handler
      #MidiParser_Event_Chunk   ;non track chunks handler
      #MidiParser_Event_Error   ;error handler
EndEnumeration
 
Enumeration ;Error codes
      #MidiParser_Error_File
      #MidiParser_Error_Header
      #MidiParser_Error_EOF
      #MidiParser_Error_Time
      #MidiParser_Error_Command
      #MidiParser_Error_SysEx
      #MidiParser_Error_System
      #MidiParser_Error_Meta
      #MidiParser_Error_Track
EndEnumeration
 
Enumeration ;Event handlers return value
      #MidiParser_Stop
      #MidiParser_Continue
EndEnumeration
 
Prototype.l HeaderHandler(Track.w, Count.w, Delta.w)
Prototype.l TrackHandler()
Prototype.l CommandHandler(Time.l, Event.l, channel.l, Param1.l, Param2.l)
Prototype.l SysExHandler(Time.l, Event.l, Size.l, *Buffer)
Prototype.l SystemHandler(Time.l, Event.l, Param.l)
Prototype.l MetaHandler(Time.l, Event.l, Size.l, *Buffer)
Prototype.l ChunkHandler(type.l, Size.l, *Buffer)
 
Global Dim EventHandlers.l(#MidiParser_Event_Error)
 
;> -------------------- <
;- MidiParser : Private
;> -------------------- <
 
Procedure.l RaiseMidiError(ErrorCode.l)
      ;if the user wants to catch it
      If EventHandlers(#MidiParser_Event_Error)
            ;then lets give him
            CallFunctionFast(EventHandlers(#MidiParser_Event_Error), ErrorCode)
      EndIf
     
      ProcedureReturn #MidiParser_Stop
EndProcedure
 
Procedure.l ParseMidiHeader(File.l, *Header.MIDIHEADER)
      Protected Result.l
      Protected Handler.HeaderHandler
      Protected Chunk.MIDICHUNK
     
      Chunk\dwType = ReadLong(File)
      Chunk\dwSize = ReadBigEndianL(File)
     
      If Chunk\dwType = #MIDI_Chunk_Header And Chunk\dwSize = SizeOf(MIDIHEADER)
            *Header\wTrack = ReadBigEndianW(File)
            *Header\wCount = ReadBigEndianW(File)
            *Header\wDelta = ReadBigEndianW(File)
           
            If *Header\wTrack >= #MIDI_Track_Single And *Header\wTrack <= #MIDI_Track_Asynchronous
                 
                  ;the header is valid so parsing continues
                  Result  = #MidiParser_Continue
                  Handler = EventHandlers(#MidiParser_Event_Header)
                 
                  ;except if the user doesn't agree
                  If Handler
                        Result = Handler(*Header\wTrack, *Header\wCount, *Header\wDelta)
                  EndIf
                 
            Else
                  ;this is not a valid midi header
                  Result = RaiseMidiError(#MidiParser_Error_Header)
            EndIf
           
      Else
            ;this is not a midi header
            Result = RaiseMidiError(#MidiParser_Error_Header)
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
Procedure.l ParseMidiTrack()
      Protected Result.l
      Protected Handler.TrackHandler
     
      Result  = #MidiParser_Continue
      Handler = EventHandlers(#MidiParser_Event_Track)
     
      If Handler
            Result = Handler()
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
Procedure.l ParseMidiCommand(File.l, Time.l, Event.l)
      Protected Result.l, channel.l
      Protected Param1.l, Param2.l
      Protected Handler.CommandHandler
     
      channel = LoNibble(Event)
      Event   = HiNibble(Event)
     
      Param1 = ReadByte(File) & $FF
     
      ;Program and After-touch messages
      ;only have a single param
      If Event <> $C And Event <> $D
            Param2 = ReadByte(File) & $FF
      EndIf
     
      If Param1 & $80 Or Param2 & $80
            ;the MSB is set to 1 for events
            RaiseMidiError(#MidiParser_Error_Command)
      Else
            ;the command is valid so parsing continues
            Result  = #MidiParser_Continue
            Handler = EventHandlers(#MidiParser_Event_Command)
           
            If Handler
                  Result = Handler(Time, Event, channel, Param1, Param2)
            EndIf
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
Procedure.l ParseMidiSysEx(File.l, Time.l, Event.l)
      Protected Result.l, Size.l, *Buffer
      Protected Handler.SysExHandler
     
      Size = ReadVarLen(File)
     
      If Size = #MIDI_VarLen_Error
            RaiseMidiError(#MidiParser_Error_SysEx)
      Else
            *Buffer = AllocateMemory(Size)
      EndIf
     
      If *Buffer
            ReadData(File, *Buffer, Size)
            Result  = #MidiParser_Continue
            Handler = EventHandlers(#MidiParser_Event_SysEx)
           
            If Handler
                  Result = Handler(Time, Event, Size, *Buffer)
            EndIf
           
            FreeMemory(*Buffer)
      Else
            FileSeek(File, Loc(File) + Size)
            Result = #MidiParser_Continue
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
Procedure.l ParseMidiSystem(File.l, Time.l, Event.l)
      Protected Result.l, Param.l
      Protected Handler.SystemHandler
     
      Select Event
            Case $F1, $F3
                  Param = ReadByte(File) & $FF
                 
                  If Param & $80
                        ;the MSB is set to 1 for events
                        RaiseMidiError(#MidiParser_Error_System)
                        Param = $FFFFFFFF
                  EndIf
                 
            Case $F2
                  Param = ReadVarLen(File)
                 
                  If VarLenSize(Param) <> 2
                        ;this event param takes two bytes
                        RaiseMidiError(#MidiParser_Error_System)
                        Param = $FFFFFFFF
                  EndIf
                 
            Case $F4
                  ;???
            Case $F5
                  ;???
                 
      EndSelect
     
      Handler = EventHandlers(#MidiParser_Event_System)
     
      If Param >= 0 And Handler
            Result = Handler(Time, Event, Param)
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
Procedure.l ParseMidiMeta(File.l, Time.l, MetaEvent.l)
      Protected Result.l, Size.l, *Buffer
      Protected Handler.MetaHandler
     
      Size = ReadVarLen(File)
     
      If Size = #MIDI_VarLen_Error
            RaiseMidiError(#MidiParser_Error_Meta)
      Else
            ;if size = 0, force memory allocation
            *Buffer = AllocateMemory(Size + 1)
      EndIf
     
      If *Buffer
            ReadData(File, *Buffer, Size)
            Result  = #MidiParser_Continue
            Handler = EventHandlers(#MidiParser_Event_Meta)
           
            If Handler
                  Result = Handler(Time, MetaEvent, Size, *Buffer)
            EndIf
           
            FreeMemory(*Buffer)
      Else
            FileSeek(File, Loc(File) + Size)
            Result = #MidiParser_Continue
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
Procedure.l ParseMidiChunk(File.l, *Chunk.MIDICHUNK)
      Protected Result.l, *Buffer
      Protected Handler.ChunkHandler
     
      If *Chunk\dwSize
            *Buffer = AllocateMemory(*Chunk\dwSize)
      EndIf
     
      If *Buffer
            ReadData(File, *Buffer, *Chunk\dwSize)
            Result  = #MidiParser_Continue
            Handler = EventHandlers(#MidiParser_Event_Chunk)
           
            If Handler
                  Result = Handler(*Chunk\dwType, *Chunk\dwSize, *Buffer)
            EndIf
           
            FreeMemory(*Buffer)
      Else
            FileSeek(File, Loc(File) + *Chunk\dwSize)
            Result = #MidiParser_Continue
      EndIf
     
      ProcedureReturn Result
EndProcedure
 
;> ------------------- <
;- MidiParser : Public
;> ------------------- <
 
ProcedureDLL.l SetMidiEventHandler(EventType.l, Callback.l)
      Protected Set.l
     
      ;If Callback is Null then the EventType is not catched (default behavior)
     
      If EventType >= #MidiParser_Event_Header And EventType <= #MidiParser_Event_Error
            EventHandlers(EventType) = Callback
            Set = #True
      EndIf
     
      ProcedureReturn Set
EndProcedure
 
ProcedureDLL.l ParseMidiFile(Filename.s)
      Protected Parsed.l, File.l, KeepParsing.l
      Protected nTracks.l, Event.l, MetaEvent.l
      Protected DeltaTime.l, Time.l, Old.l, Loc.l
      Protected Chunk.MIDICHUNK
      Protected Header.MIDIHEADER
     
      File = ReadFile(#PB_Any, Filename)
     
      If File
            KeepParsing = ParseMidiHeader(File, Header)
           
            ;
            ; Chunk loop (catch all chunks till the end of file)
            ;
            While KeepParsing And Not Eof(File)
                 
                  ;if not EOF then there must be another chunk
                  If Lof(File) - Loc(File) < SizeOf(MIDICHUNK)
                        KeepParsing = RaiseMidiError(#MidiParser_Error_EOF)
                  Else
                        Chunk\dwType = ReadLong(File)
                        Chunk\dwSize = ReadBigEndianL(File)
                  EndIf
                 
                  ;if remaining size is enough, identify the chunk
                  If KeepParsing And Lof(File) - Loc(File) < Chunk\dwSize
                       
                        KeepParsing = RaiseMidiError(#MidiParser_Error_EOF)
                       
                  ElseIf KeepParsing
                       
                        Select Chunk\dwType
                              Case #MIDI_Chunk_Track
                                    ;inform the user that a new track is about to be parsed
                                    KeepParsing = ParseMidiTrack()
                                    nTracks + 1 ;internal track counter
                              Case #MIDI_Chunk_Header
                                    ;this chunk only append at the begining of the file
                                    KeepParsing = RaiseMidiError(#MidiParser_Error_Header)
                              Default
                                    ;we don't know this chunk...
                                    KeepParsing = ParseMidiChunk(File, Chunk)
                        EndSelect
                       
                  EndIf
                 
                  ;
                  ; Track parser (catch all events till the end of the track)
                  ;
                  If KeepParsing And Chunk\dwType = #MIDI_Chunk_Track
                       
                        ;exprected file location at the end of the track
                        Loc = Loc(File) + Chunk\dwSize
                       
                        ;reset values
                        Time = 0
                        MetaEvent = 0
                       
                        While Not (Event = $FF And MetaEvent = $2F) ;While Not EndOfTrack
                             
                              DeltaTime = ReadVarLen(File)
                              Time + DeltaTime
                             
                              If DeltaTime = #MIDI_VarLen_Error
                                    RaiseMidiError(#MidiParser_Error_Time)
                                    Break
                              EndIf
                             
                              Old   = Event
                              Event = ReadByte(File) & $FF
                             
                              ;Events have MSB set to 1 (ie >= $80)
                              ;If not, it's a param for the next event
                              ;the next event is the same as the previous
                              If Event < $80
                                    FileSeek(File, Loc(File)-1)
                                    Event = Old
                              EndIf
                             
                              Select Event
                                    Case $80 To $EF
                                          KeepParsing = ParseMidiCommand(File, Time, Event)
                                         
                                    Case $F0, $F7
                                          KeepParsing = ParseMidiSysEx(File, Time, Event)
                                         
                                    Case $FF
                                          MetaEvent = ReadByte(File) & $FF
                                         
                                          If MetaEvent & $80
                                                ;the MSB is set to 1 for events
                                                KeepParsing = RaiseMidiError(#MidiParser_Error_Meta)
                                          Else
                                                KeepParsing = ParseMidiMeta(File, Time, MetaEvent)
                                          EndIf
                                         
                                    Default
                                          KeepParsing = ParseMidiSystem(File, Time, Event)
                                         
                              EndSelect
                             
                              ;the user doesn't want to continue ?
                              ;an error has occured ?
                              If Not KeepParsing
                                    ;whatever... just stop parsing
                                    Break
                              EndIf
                             
                        Wend ;While Not EndOfTrack
                       
                        ;the chunk size is not the specified size
                        If Loc <> Loc(File)
                              KeepParsing = RaiseMidiError(#MidiParser_Error_Track)
                        EndIf
                       
                  EndIf ;Track parser
                 
            Wend ;Chunk loop
           
            ;the number of tracks is not valid
            If nTracks <> Header\wCount
                  KeepParsing = RaiseMidiError(#MidiParser_Error_Track)
            EndIf
           
            ;it's finally over ^_^
            If KeepParsing
                  Parsed = #True
            EndIf
           
            CloseFile(File)
      Else
            RaiseMidiError(#MidiParser_Error_File)
      EndIf
     
      ProcedureReturn Parsed
EndProcedure
 
;> ---------------- <
;- MidiParser : EOF
;> ---------------- <



в качестве примера работы там давали:
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
IncludeFile "lib_midi.pb"
DisableExplicit
 
Procedure ShowMidiError(code)
      Select code
            Case #MidiParser_Error_File
                  Debug "Error : Cannot open the file"
            Case #MidiParser_Error_Header
                  Debug "Error : Header Error"
            Case #MidiParser_Error_EOF
                  Debug "Error : Unexpected EOF"
            Case #MidiParser_Error_Time
                  Debug "Error : Invalid Delta-Time"
            Case #MidiParser_Error_Command
                  Debug "Error : Command param"
            Case #MidiParser_Error_SysEx
                  Debug "Error : System Exclusive Event"
            Case #MidiParser_Error_System
                  Debug "Error : System Event param"
            Case #MidiParser_Error_Meta
                  Debug "Error : Meta-event error"
      EndSelect
EndProcedure
 
Procedure ShowMidiHeader(type, Count, Delta)
      Debug "FormatType : " + Str(type)
      Debug "NumberOfTracks : " + Str(Count)
      Debug "DeltaTimeIncrement (BPM ?) : " + StrD(6E4 / Delta)
      Debug "---"
     
      ProcedureReturn #MidiParser_Continue
EndProcedure
 
Procedure ShowMidiTrack()
      Debug "TrackChunk"
     
      ProcedureReturn #MidiParser_Continue
EndProcedure
 
Procedure ShowMidiChunk(type, Size, *Buffer)
      Debug "Unknown chunk : " + PeekS(@type, 4)
     
      ProcedureReturn #MidiParser_Continue
EndProcedure
 
Procedure ShowMidiCommand(Time, Event, channel, Param1, Param2)
     
      Select Event
            Case $8
                  Debug Str(Time) + " -> Channel : " + Str(channel) + " Note Off : " + Str(Param1) + " Velocity : " + Str(Param2)
            Case $9
                  Debug Str(Time) + " -> Channel : " + Str(channel) + " Note On : " + Str(Param1) + " Velocity : " + Str(Param2)
      EndSelect
     
      ProcedureReturn #MidiParser_Continue
EndProcedure
 
Procedure ShowMidiMeta(Time, meta, Size, *Buffer)
     
      Select meta
            Case $51
                  tempo = PeekBigEndianN(*Buffer, Size)
                  Debug Str(Time) + " -> Set Tempo (BPM) : " + StrD(6E7 / tempo)
                 
            Case $2F
                  Debug "EndOfTrack"
                  Debug "---"
                 
      EndSelect
     
      ProcedureReturn #MidiParser_Continue
EndProcedure
 
SetMidiEventHandler(#MidiParser_Event_Error,   @ShowMidiError()  )
SetMidiEventHandler(#MidiParser_Event_Header,  @ShowMidiHeader() )
SetMidiEventHandler(#MidiParser_Event_Track,   @ShowMidiTrack()  )
SetMidiEventHandler(#MidiParser_Event_Command, @ShowMidiCommand())
SetMidiEventHandler(#MidiParser_Event_Meta,    @ShowMidiMeta()   )
 
MidiFileName$ = OpenFileRequester("Open midi file", "", "Midi|*.mid;*.midi", 0)
 
If ParseMidiFile(MidiFileName$)
      Debug GetFilePart(MidiFileName$) + " parsing is over"
Else
      Debug "An error as occured while parsing " + GetFilePart(MidiFileName$)
EndIf



однако в этом коде нет пункта вывода информации об инструменте. в другом коде, кажись в код архиве есть подобное... но я ничерта понять не могу как они это делают :)
Код:
1
2
3
ElseIf TEvent >=$C0 And TEvent <=$CF 
            MProgramNumber = ReadByte(0) : If MProgramNumber <0 : MProgramNumber + 256 : EndIf
            MidiEvent$ ="Program Change, channel "+Str(TEvent&$F)+" - ProgramNumber : "+Str(MProgramNumber)+" : "+MidiInstrument$(MProgramNumber)


как бы этот кусочек докрутить до этой библиотеки?


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Вс авг 02, 2015 2:17 am 
Не в сети
профессор

Зарегистрирован: Чт авг 05, 2010 2:36 pm
Сообщений: 469
Откуда: Донецк
Благодарил (а): 47 раз.
Поблагодарили: 11 раз.
SereZa
эта либа генерит мидифайл или только разбирает по событиям?
PS: Я как лох с андроида могу пока только читать форум и без пурика немогу ничего сам проверить :(

_________________
PureBasic 5.60 X86, RfoBasic 90, Tinycc 0.97, Asus K54C Intel i7 2.7 ghz, 8 gb ddr3, Intel HD 3000, Windows XP SP3, Windows 10 x64, Nexus 4 and v5.1.1.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Вс авг 02, 2015 8:37 am 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
разбирает.

оказалось не туда вставлял :) однако теперь затык в другом:
ReadByte(File), я так понимаю, сдвигает метку для чтение на 1 байт вперед, следовательно первый канал с инструментом он читает нормально, а потом весь последующий код умирает :) как вернуть эту метку на 1 байт назад после этого чтения ReadByte(File)?

все. вроде разобрался :) нужно добавить один кейс в команду ShowMidiCommand - 12
Код:
1
2
3
4
5
6
7
8
9
10
Procedure ShowMidiCommand(Time, Event, channel, Param1, Param2)
     
      Select Event
         
        Case 12
          Debug "channel " + Str(channel) + "; инструмент " + Str(Param1)
         
         
        Case $8
          Debug Str(Time) + " -> Chan.......


также надо будет добавить массив инструментов в библиотеку, чтобы он мог писать не просто номер, а название :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Вс авг 02, 2015 10:55 am 
Не в сети
PureBasic Coder
Аватар пользователя

Зарегистрирован: Чт ноя 10, 2011 10:50 am
Сообщений: 4049
Откуда: Ростов-на-Дону
Благодарил (а): 70 раз.
Поблагодарили: 81 раз.
Пункты репутации: 24
Еще FileSeek есть

_________________
Пурик - лучший язык программирования


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Пн авг 03, 2015 3:08 pm 
Не в сети
профессор

Зарегистрирован: Вт мар 24, 2009 11:54 am
Сообщений: 357
Благодарил (а): 14 раз.
Поблагодарили: 18 раз.
Пункты репутации: 19
К вопросу об инструментах. Каждому инструменту присвоен номер. Если послать команду $C0 на один из 16 каналов с указание номера инструмента то на этом канале будет звучать присвоенный инструмент.

Процедура утановки инструмента
Код:
1
2
3
Procedure SetInstrument(channel,instrument) 
  MidiOutMessage(hMidiOut, $C0,  channel, instrument, 0)
EndProcedure



Список инструментов (от 0 и т.д.):
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
DataSection  
SMI:
  Data$ "Ac Gd Piano"  
  Data$ "Bght Ac Piano"  
  Data$ "El Gd Piano"  
  Data$ "Honky-tonk Piano"  
  Data$ "Electric Piano 1"  
  Data$ "Electric Piano 2"  
  Data$ "Harpsichord"  
  Data$ "Clavi"  
  Data$ "Celesta"  
  Data$ "Glockenspiel"  
  Data$ "Music Box"  
  Data$ "Vibraphone"  
  Data$ "Marimba"  
  Data$ "Xylophone"  
  Data$ "Tubular Bells"  
  Data$ "Dulcimer"  
  Data$ "Drawbar Organ"  
  Data$ "Percussive Organ"  
  Data$ "Rock Organ"  
  Data$ "Church Organ"  
  Data$ "Reed Organ"  
  Data$ "Accordion"  
  Data$ "Harmonica"  
  Data$ "Tango Accordion"  
  Data$ "Ac Guitar (nylon)"  
  Data$ "Ac Guitar (steel)"  
  Data$ "El Guitar (jazz)"  
  Data$ "El Guitar (clean)"  
  Data$ "El Guitar (muted)"  
  Data$ "Overdrive Guitar"  
  Data$ "Distortion Guitar"  
  Data$ "Guitar harmonic"  
  Data$ "Ac Bass"  
  Data$ "El Bass (finger)"  
  Data$ "El Bass (pick)"  
  Data$ "Fretless Bass"  
  Data$ "Slap Bass 1"  
  Data$ "Slap Bass 2"  
  Data$ "Synth Bass 1"  
  Data$ "Synth Bass 2"  
  Data$ "Violin"  
  Data$ "Viola"  
  Data$ "Cello"  
  Data$ "Contrabasse"  
  Data$ "Tremolo Strings"  
  Data$ "Pizzicato Strings"  
  Data$ "Orchestral Harp"  
  Data$ "Timpani"  
  Data$ "String Ensemble 1"  
  Data$ "String Ensemble 2"  
  Data$ "SynthStrings 1"  
  Data$ "SynthStrings 2"  
  Data$ "Choir Aahs"  
  Data$ "Voice Oohs"  
  Data$ "Synth Voice"  
  Data$ "Orchestra Hit"  
  Data$ "Trumpet"  
  Data$ "Trombone"  
  Data$ "Tuba"  
  Data$ "Muted Trumpet"  
  Data$ "French Horn"  
  Data$ "Brass Section"  
  Data$ "SynthBrass 1"  
  Data$ "SynthBrass 2"  
  Data$ "Soprano Sax"  
  Data$ "Alto Sax"  
  Data$ "Tenor Sax"  
  Data$ "Baritone Sax"  
  Data$ "Oboe"  
  Data$ "English Horn"  
  Data$ "Bassoon"  
  Data$ "Clarinet"  
  Data$ "Piccolo"  
  Data$ "Flute"  
  Data$ "Recorder"  
  Data$ "Pan Flute"  
  Data$ "Blown Bottle"  
  Data$ "Shakuhachi"  
  Data$ "Whistle"  
  Data$ "Ocarina"  
  Data$ "Lead 1 (square)"  
  Data$ "Lead 2 (sawtooth)"  
  Data$ "Lead 3 (calliope)"  
  Data$ "Lead 4 (chiff)"  
  Data$ "Lead 5"  
  Data$ "Lead 6 (voice)"  
  Data$ "Lead 7 (fifths)"  
  Data$ "Lead 8 (bass + lead)"  
  Data$ "Pad 1 (new age)"  
  Data$ "Pad 2 (warm)"  
  Data$ "Pad 3 (polysynth)"  
  Data$ "Pad 4 (choir)"  
  Data$ "Pad 5 (bowed"  
  Data$ "Pad 6 (metallic)"  
  Data$ "Pad 7 (halo)"  
  Data$ "Pad 8 (sweep)"  
  Data$ "FX 1 (rain)"  
  Data$ "FX 2 (soundtrack)"  
  Data$ "FX 3 (crystal)"  
  Data$ "FX 4 (atmosphere)"  
  Data$ "FX 5 (brightness)"  
  Data$ "FX 6 (goblins)"  
  Data$ "FX 7 (echoe)"  
  Data$ "FX 8 (sci-fi)"  
  Data$ "Sitar"  
  Data$ "Banjo"  
  Data$ "Shamisen"  
  Data$ "Koto"  
  Data$ "Kalimba"  
  Data$ "Bag pipe"  
  Data$ "Fiddle"  
  Data$ "Shanai"  
  Data$ "Tinkle Bell"  
  Data$ "Agogo"  
  Data$ "Steel Drums"  
  Data$ "Woodblock"  
  Data$ "Taiko Drum"  
  Data$ "Melodic Tom"  
  Data$ "Synth Drum"  
  Data$ "Reverse Cymba"  
  Data$ "Guitar Fret Noise"  
  Data$ "Breath Noise"  
  Data$ "Seashore"  
  Data$ "Bird Tweet"  
  Data$ "Telephone Ring"  
  Data$ "Helicopter"  
  Data$ "Applause"  
  Data$ "Gunshot"  
EndDataSection



Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Чт авг 06, 2015 3:12 pm 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
тут у меня закавыка одна... нет ли какого-то нюанса в использовании миди? поясняю:
когда мой проигрыватель проигрывает специальный файл, где есть разметка по нотам и длительностям - в миди все без проблем. однако если на дорожке есть использование сэмпла, а не миди инструмента - то этот сэмпл, скатина, играет чуть раньше.

поскольку формат аудио чуток не подходит, то стандартные PB плей команды не работают. использовать приходится через:
sndPlaySound_(*samp,#SND_MEMORY | #SND_ASYNC | #SND_NODEFAULT)

если сэмплы заменить на ноты миди, с сохранением тайминга - то все играет нормально. а вот сэмпл чуть раньше. и это торопление всегда одинакового - 3 единицы времени. то есть если я все сэмплы передвину на +3 в массиве - то все играет замечательно. вот в связи с чем вопрос - нет ли какой-то проблемы в PB, связанной с MIDI - что это самое миди начинает играть чуть с запозданием? то есть wav'ka на самом деле стартует вовремя, а вот миди тормозит.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Чт авг 06, 2015 4:24 pm 
Не в сети
профессор

Зарегистрирован: Вт мар 24, 2009 11:54 am
Сообщений: 357
Благодарил (а): 14 раз.
Поблагодарили: 18 раз.
Пункты репутации: 19
Была такая проблема в БитБоксе сдвинул ВАВку по времени, т.е. синхронизировал :wink: и все стало на свои места.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Пт авг 07, 2015 9:06 pm 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1694
Откуда: Алматы
Благодарил (а): 15 раз.
Поблагодарили: 46 раз.
Пункты репутации: 5
и еще момент. насколько я понял в VGM Music Maker инструмент создается путем кручения кучи параметров. видимо можно получить любое звучание, если знать куда крутить :) вот собственно вопрос: не существует ли специальной таблицы этих параметров для VGM для каждого из 127 midi инструментов? чтобы звучание как можно ближе к PC звучанию миди. понятно что Ямаха какая-нить рулит, и там миди звучит гораздо круче - однако хотелось бы поближе к PC варианту...


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Сб авг 08, 2015 3:29 pm 
Не в сети
GameC@Soft
Аватар пользователя

Зарегистрирован: Сб сен 22, 2007 12:45 pm
Сообщений: 1085
Откуда: Я из лесу вышел, и сразу зашел, в босоножках дырявых и взлядом ночным.
Благодарил (а): 1 раз.
Поблагодарили: 2 раз.
Пункты репутации: 0
А я делал пианинко для андроида.. )
Значит взял мидишку, потом спецутилитой конвертнул в txt файл, после написал простенький парсер, который сохранял в bin файл, получался почти тот же midi но собственного разлива. После в Unity3D я гружу это чудо файл bin, создаю массив данных, упорядочиваю, подвязываю под каждую ноту wav файл... После ноты летят вниз, а тебе надо нажимать на нужные ноты на экране, и ты играешь уже Бетховена к Элизе...
https://www.youtube.com/watch?v=2S5_FQB9BwQ
https://www.youtube.com/watch?v=OIunEx3PbA0

_________________
"Самый большой глюк в PureBasic - это твоя голова...." (с) Артем
Мой сайт: http://feelzone.org.ua/


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Синтез MIDI
СообщениеДобавлено: Сб авг 08, 2015 9:38 pm 
Не в сети
профессор

Зарегистрирован: Ср янв 14, 2009 4:12 pm
Сообщений: 2002
Благодарил (а): 12 раз.
Поблагодарили: 101 раз.
Пункты репутации: 43
Артём писал(а):
После ноты летят вниз, а тебе надо нажимать на нужные ноты на экране, и ты играешь уже Бетховена к Элизе...

Что-то у вас нажатие клавиш ну никак с мелодией не совпадают. Вы бы выложили скомпилированное приложение, а мы бы сами попробовали Людвига сыграть. А так - фотошоп какой-то

_________________
Всё должно быть просто, настолько просто, насколько возможно, но не проще. (c) Альберт Эйнштейн
Изображение


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 41 ]  На страницу Пред.  1, 2, 3  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB