سؤال

أنا أكتب برنامج Windows باستخدام C ++ و Windows API ، وأحاول طوابير رسائل MIDI في دفق MIDI ، لكنني أتلقى خطأً غريبًا عندما أحاول القيام بذلك. إذا استخدمت midiOutShortMsg لإرسال رسالة MIDI غير المطلقة إلى الدفق ، فهي تعمل بشكل صحيح. لكن، midiStreamOut يعيد دائمًا رمز الخطأ 68 ، وهو #defineد ل MCIERR_WAVE_OUTPUTUNSPECIFIED. midiOutGetErrorText يعطي الوصف التالي للخطأ:

يشير إعداد MIDI Mapper الحالي إلى جهاز MIDI غير مثبت على النظام. استخدم MIDI MAPPER لتحرير الإعداد.

أنا أستخدم Windows 7 (64 بت) وحاولت فتح دفق MIDI مع معرفات الجهاز لكل من MIDI_MAPPER وجميع أجهزة إخراج MIDI الأربعة على نظامي ، وما زلت تتلقى نفس رسالة الخطأ.

هنا هو الرمز لفتح دفق MIDI:

UINT device_id = MIDI_MAPPER; //Also tried 0, 1, 2 and 3
midiStreamOpen( &midi, &device_id, 1, ( DWORD_PTR )hwnd, 0, CALLBACK_WINDOW );

فيما يلي الرمز لإرسال رسالة MIDI:

MIDIHDR header;
MIDIEVENT *event;

event = ( MIDIEVENT * )malloc( sizeof( *event ) );
event->dwDeltaTime = delta_time;
event->dwStreamID = 0;
event->dwEvent = ( MEVT_F_SHORT | MEVT_SHORTMSG ) << 24 | ( msg & 0x00FFFFFF );

header.lpData = ( LPSTR )event;
header.dwBufferLength = sizeof( *event );
header.dwBytesRecorded = sizeof( *event );
header.dwUser = 0;
header.dwFlags = 0;
header.dwOffset = 0;

midiOutPrepareHeader( ( HMIDIOUT )midi, &header, sizeof( header ) );
midiStreamOut( midi, &header, sizeof( header ) );

كيف يمكنني حل هذه المشكلة؟

هل كانت مفيدة؟

المحلول

كانت المشكلة أنني كنت أستخدم بنية الحدث بأكملها كمخزن مؤقت لتيار MIDI. اتضح أن العضو الرابع في الهيكل ، dwParms, ، يجب حذفها بالفعل من الرسائل القصيرة. لتصحيح الرمز في السؤال المنشور ، يمكن تغيير سطرين من الكود إلى ما يلي:

header.dwBufferLength = sizeof( *event ) - sizeof( event->dwParms );
header.dwBytesRecorded = sizeof( *event ) - sizeof( event->dwParms );

عند إضافة أحداث متعددة إلى الدفق ، من الأسهل بكثير استخدام مجموعة من DWORDS بدلا من أن تزعج مع MIDIEVENT الهياكل.

لأي شخص آخر يقوم ببرمجة MIDI باستخدام Windows API ، احذر من أن بعض وثائق MSDN مضللة أو غير كافية أو خاطئة تمامًا.

وثائق MIDIEVENT الهيكل يقول ما يلي:

dwparms

إذا كان Dwevent يحدد mevt_f_short ، فلا تستخدم هذا العضو في المخزن المؤقت للتيار.

هذا غامض لأنه ليس من الواضح أن "الاستخدام" يهدف إلى يعني "تشمل" بدلاً من "تحديد".

فيما يلي عيبان آخران في الوثائق التي يجب أن يكون المبرمجون على دراية بها:

Dwevent

رمز الحدث والمعلمات الحدث أو الطول. [...] يحتوي البايت العالي لهذا العضو على أعلام ورمز الحدث. يجب تحديد علامة mevt_f_long أو mevt_f_short. علامة mevt_f_callback اختيارية.

عندما يتم فحص ملفات الرأس ، MEVT_F_ تعاريف المعالج المسبق تحدد بالفعل كاملة DWORDبدلاً من مجرد علامات فردية ، لذلك في الكود الخاص بي في السؤال ، كان يجب أن يكون السطر الذي يحدد هذا العضو كما يلي:

event->dwEvent = MEVT_F_SHORT | MEVT_SHORTMSG << 24 | ( msg & 0x00FFFFFF );

بالإضافة إلى ذلك ، اتضح أيضًا أن الذاكرة التي تحتوي على بنية MidiHDR يجب الاحتفاظ بها حتى ينتهي المخزن المؤقت من اللعب ، لذلك يجب تخصيصه على الكومة بدلاً من المكدس لمعظم التطبيقات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top