 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Pete Goodwin Guest
|
Posted: Fri Apr 29, 2005 8:12 am Post subject: midistream and Windows XP? |
|
|
Are there any known issues with the midistream API and Windows XP? I'm
getting timing problems as I use midiStreamOut.
A simple drum pattern consists of:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
Bass Drum x . . . x . . . x . . . x . . .
Snare . . . . x . . . . . . . x . . .
Closed Hi Hats x . x . x . x . x . x . x . x .
What I'm sending via midiStreamOut:
(PPQN is 96)
Delta
(1)
0 Bass note on
0 Hit Hats note on
24 Bass note off
24 Hit Hats note off
(callback)
(2)
24 NOP
(callback)
(3)
0 Hi Hats note on
24 Hi Hats note off
(callback)
(4)
24 NOP
and so on...
However, it doesn't sound right, the timing is off.
The NOP seems to work, also I did try a dummy note to channel 0, as in:
0 0x00003090
24 0x00003080
which works as well as the NOP.
The (callback) is actually a MM_MOM_DONE message sent to my main form.
Here, I do the following:
midiUnprepeareHeader(...)
....queue up next set of notes
midiStreamOut(...)
What am I doing wrong? Am I sending too little, do I need to send more
notes through, something like:
Delta
(1)
0 Bass note on
0 Hit Hats note on
24 Bass note off
24 Hit Hats note off
(2)
(3)
48 Hi Hats note on
72 Hi Hats note off
(4)
96 NOP
(callback)
Pete
|
|
| Back to top |
|
 |
Pete Goodwin Guest
|
Posted: Fri Apr 29, 2005 10:53 am Post subject: Re: midistream and Windows XP? |
|
|
Here's a sample application to demonstrate:
-------------------------------------------------------------------------------------------------------
- main.pas -
unit main;
interface
uses
Windows, MMSystem, Messages, SysUtils, Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls;
const
PPQN = 96;
Dur16th = PPQN div 4;
NoteOn = $99;
NoteOff = $89;
Velocity = 96 shl 16;
VelocityMax = 127 shl 16;
BassDrum = 35 shl 8;
ClosedHiHat = 42 shl 8;
Snare = 38 shl 8;
BassNoteOn = Velocity + BassDrum + NoteOn;
BassNoteOff = Velocity + BassDrum + NoteOff;
HiHatOn = Velocity + ClosedHiHat + NoteOn;
HiHatOff = Velocity + ClosedHiHat + NoteOff;
SnareOn = Velocity + Snare + NoteOn;
SnareOff = Velocity + Snare + NoteOff;
BassMaxOn = VelocityMax + BassDrum + NoteOn;
HiHatMaxOn = VelocityMax + ClosedHiHat + NoteOn;
SnareMaxOn = VelocityMax + Snare + NoteOn;
DummyNoteOn = $4090;
DummyNoteOff = $4080;
type
TMIDIEvent = record
dwDeltaTime: DWORD;
dwStreamID: DWORD;
dwEvent: DWORD;
end;
TDrumEvent = record
lpData: pointer;
size: Cardinal;
end;
const
Drum1: array [0..3] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: BassNoteOn),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: BassNoteOff),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: HiHatOff)
);
Drum2: array [0..1] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: HiHatOff)
);
Drum3: array [0..5] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: BassMaxOn),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatMaxOn),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: SnareMaxOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: BassNoteOff),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: HiHatOff),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: SnareOff)
);
DrumNOPDummy: array [0..1] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: DummyNoteOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent:
DummyNoteOff)
);
DrumNOP: TMIDIEvent =
(
dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: MEVT_NOP
shl 24
);
DrumTable: array [1..16] of TDrumEvent =
(
(lpData: @Drum1; size: sizeof(Drum1)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum2; size: sizeof(Drum2)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum3; size: sizeof(Drum1)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum2; size: sizeof(Drum2)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum1; size: sizeof(Drum1)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum2; size: sizeof(Drum2)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum3; size: sizeof(Drum1)),
(lpData: @DrumNOP; size: sizeof(DrumNOP)),
(lpData: @Drum2; size: sizeof(Drum2)),
(lpData: @DrumNOP; size: sizeof(DrumNOP))
);
type
TMainForm = class(TForm)
PlayBtn: TButton;
StopBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure PlayBtnClick(Sender: TObject);
procedure StopBtnClick(Sender: TObject);
private
{ Private declarations }
procedure MOMDONE(var msg: TMessage); message MM_MOM_DONE;
public
{ Public declarations }
stream: HMIDISTRM;
header: TMIDIHDR;
note: integer;
end;
var
MainForm: TMainForm;
implementation
{$R *.DFM}
procedure Check(status: MMResult);
begin
if status <> MMSYSERR_NOERROR then
MessageDlg('MIDI Stream error: ' + IntToStr(status), mtError,
[mbOK], 0);
end;
procedure TMainForm.MOMDONE(var msg: TMessage);
begin
Check(midiOutUnprepareHeader(stream, @header, sizeof(TMIDIHDR)));
header.lpData := DrumTable[note].lpData;
header.dwBufferLength := DrumTable[note].size;
header.dwBytesRecorded := DrumTable[note].size;
Check(midiOutPrepareHeader(stream, @header, sizeof(TMIDIHDR)));
Check(midiStreamOut(stream, @header, sizeof(TMIDIHDR)));
inc(note);
if note > 16 then note := 1;
end;
procedure TMainForm.FormCreate(Sender: TObject);
var
device: integer;
timediv: TMIDIPROPTIMEDIV;
tempo: TMIDIPROPTEMPO;
begin
device := 0;
Check(midiStreamOpen(@stream, @device, 1, Handle, 0, CALLBACK_WINDOW));
timediv.cbStruct := sizeof(TMIDIPROPTIMEDIV);
timediv.dwTimeDiv := PPQN;
Check(midiStreamProperty(stream, @timediv, MIDIPROP_SET or
MIDIPROP_TIMEDIV));
tempo.cbStruct := sizeof(TMIDIPROPTEMPO);
tempo.dwTempo := $0007A120;
Check(midiStreamProperty(stream, @tempo, MIDIPROP_SET or
MIDIPROP_TEMPO));
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
Check(midiStreamClose(stream));
end;
procedure TMainForm.PlayBtnClick(Sender: TObject);
begin
note := 1;
header.lpData := DrumTable[note].lpData;
header.dwBufferLength := DrumTable[note].size;
header.dwBytesRecorded := DrumTable[note].size;
Check(midiOutPrepareHeader(stream, @header, sizeof(TMIDIHDR)));
Check(midiStreamOut(stream, @header, sizeof(TMIDIHDR)));
Check(midiStreamRestart(stream));
inc(note);
end;
procedure TMainForm.StopBtnClick(Sender: TObject);
begin
Check(midiStreamStop(stream));
Check(midiOutUnprepareHeader(stream, @header, sizeof(TMIDIHDR)));
end;
end.
-------------------------------------------------------------------------------------------------------
- main.dfm -
object MainForm: TMainForm
Left = 193
Top = 114
Width = 378
Height = 147
Caption = 'MIDI Streaming sample'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
Position = poDefaultPosOnly
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object PlayBtn: TButton
Left = 8
Top = 8
Width = 75
Height = 25
Caption = '&Play'
TabOrder = 0
OnClick = PlayBtnClick
end
object StopBtn: TButton
Left = 112
Top = 8
Width = 75
Height = 25
Caption = '&Stop'
TabOrder = 1
OnClick = StopBtnClick
end
end
----------------------------------------------------------------------------------------------------
- midistrm.dpr -
program midistr;
uses
Forms,
main in 'main.pas' {MainForm};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
|
|
| Back to top |
|
 |
Pete Goodwin Guest
|
Posted: Fri Apr 29, 2005 10:16 pm Post subject: Re: midistream and Windows XP? |
|
|
The penny drops...
I had the dwDeltaTime parameter wrong. It should be:
Drum1: array [0..3] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: BassNoteOn),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: BassNoteOff),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatOff)
);
Drum2: array [0..1] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: HiHatOff)
);
Drum3: array [0..5] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: BassMaxOn),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatMaxOn),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: SnareMaxOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: BassNoteOff),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: HiHatOff),
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: SnareOff)
);
DrumNOPDummy: array [0..1] of TMIDIEvent =
(
(dwDeltaTime: 0; dwStreamID: 0; dwEvent: DummyNoteOn),
(dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: DummyNoteOff)
);
DrumNOP: TMIDIEvent =
(
dwDeltaTime: Dur16th; dwStreamID: 0; dwEvent: MEVT_NOP
shl 24
);
Since the delta time is the time difference between the current and the
last event, not the note!
Now it plays correctly. Until I click on stop, then play, then I get
error 65 - MIDIERR_STILLPLAYING - uh, how is something still playing, I
just did a midiStreamStop?
Pete
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|