BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

midistream and Windows XP?

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Multimedia
View previous topic :: View next topic  
Author Message
Pete Goodwin
Guest





PostPosted: Fri Apr 29, 2005 8:12 am    Post subject: midistream and Windows XP? Reply with quote



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





PostPosted: Fri Apr 29, 2005 10:53 am    Post subject: Re: midistream and Windows XP? Reply with quote



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





PostPosted: Fri Apr 29, 2005 10:16 pm    Post subject: Re: midistream and Windows XP? Reply with quote



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
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Multimedia All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.