static void test_midi_outfns(HWND hwnd) { HMIDIOUT hm; MMRESULT rc; UINT udev, ndevs = midiOutGetNumDevs(); rc = midiOutOpen(&hm, ndevs, 0, 0, CALLBACK_NULL); ok(rc==MMSYSERR_BADDEVICEID, "midiOutOpen udev>max rc=%s\n", mmsys_error(rc)); if (!rc) { rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); } if (!ndevs) { MIDIOUTCAPSA capsA; skip("Found no MIDI out device\n"); rc = midiOutGetDevCapsA(MIDIMAPPER, &capsA, sizeof(capsA)); /* GetDevCaps and Open must return compatible results */ ok(rc==MMSYSERR_BADDEVICEID || broken(rc==MMSYSERR_NODRIVER /*nt,w2k*/), "midiOutGetDevCaps MAPPER with no MIDI rc=%s\n", mmsys_error(rc)); rc = midiOutOpen(&hm, MIDIMAPPER, 0, 0, CALLBACK_NULL); if (rc==MIDIERR_INVALIDSETUP) todo_wine /* Wine without snd-seq */ ok(rc==MMSYSERR_BADDEVICEID || broken(rc==MMSYSERR_NODRIVER /*w2k*/), "midiOutOpen MAPPER with no MIDI rc=%s\n", mmsys_error(rc)); else ok(rc==MMSYSERR_BADDEVICEID || broken(rc==MMSYSERR_NODRIVER /*w2k sound disabled*/), "midiOutOpen MAPPER with no MIDI rc=%s\n", mmsys_error(rc)); if (!rc) { rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); } return; } trace("Found %d MIDI OUT devices\n", ndevs); test_midi_mci(hwnd); for (udev=0; udev < ndevs; udev++) { MIDIOUTCAPSA capsA; rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA)); if (rc || strcmp(capsA.szPname, "Creative Sound Blaster MPU-401") != 0 || ! on_vmware()) { trace("** Testing device %d\n", udev); test_midiOut_device(udev, hwnd); Sleep(800); /* Let the synth rest */ test_midiStream(udev, hwnd); Sleep(800); } else win_skip("Skipping this device on VMware, driver problem\n"); } trace("** Testing MIDI mapper\n"); test_midiOut_device(MIDIMAPPER, hwnd); Sleep(800); test_midiStream(MIDIMAPPER, hwnd); }
/************************************************************************** * MIDIMAP_drvOpen [internal] */ static DWORD MIDIMAP_drvOpen(LPSTR str) { MIDIOUTCAPSA moc; unsigned dev, i; if (midiOutPorts) return 0; numMidiOutPorts = midiOutGetNumDevs(); midiOutPorts = HeapAlloc(GetProcessHeap(), 0, numMidiOutPorts * sizeof(MIDIOUTPORT)); for (dev = 0; dev < numMidiOutPorts; dev++) { if (midiOutGetDevCapsA(dev, &moc, sizeof(moc)) == 0L) { strcpy(midiOutPorts[dev].name, moc.szPname); midiOutPorts[dev].loaded = 0; midiOutPorts[dev].hMidi = 0; midiOutPorts[dev].uDevID = 0; midiOutPorts[dev].lpbPatch = NULL; for (i = 0; i < 16; i++) midiOutPorts[dev].aChn[i] = i; } else { midiOutPorts[dev].loaded = -1; } } return 1; }
void midiInitialize() { MIDIINCAPSA inCap; MIDIOUTCAPSA outCap; int num; memset(&midi, 0, sizeof(midi)); midi.enabled = 1; num = midiOutGetNumDevs(); if (num > 0 && midiOutGetDevCapsA(MIDI_MAPPER, &outCap, sizeof(outCap)) == MMSYSERR_NOERROR) { int i; midi.out.dev = (DevInfo*)calloc(1, (num + 1) * sizeof(DevInfo)); strcpy(midi.out.dev[0].name, outCap.szPname); midi.out.dev[0].id = MIDI_MAPPER; strcpy(midi.out.dev[0].idString, "midi-out"); midi.out.count++; for (i = 0; i < num; i++) { if (midiOutGetDevCapsA(i, &outCap, sizeof(outCap)) == MMSYSERR_NOERROR) { strcpy(midi.out.dev[midi.out.count].name, outCap.szPname); midi.out.dev[midi.out.count].id = i; sprintf(midi.out.dev[midi.out.count].idString, "midi-out-%u", i); midi.out.count++; } } } num = midiInGetNumDevs(); if (num > 0) { int i; midi.in.dev = (DevInfo*)calloc(1, num * sizeof(DevInfo)); for (i = 0; i < num; ++i) { if (midiInGetDevCapsA(i, &inCap, sizeof(inCap)) == MMSYSERR_NOERROR) { strcpy(midi.in.dev[midi.in.count].name, inCap.szPname); midi.in.dev[midi.in.count].id = i; sprintf(midi.in.dev[midi.in.count].idString, "midi-in-%u", i); midi.in.count++; } } } }
static bool IgnoreMIDIVolume(UINT id) { MIDIOUTCAPSA caps; if (MMSYSERR_NOERROR == midiOutGetDevCapsA(id, &caps, sizeof(caps))) { if (caps.wTechnology == MIDIDEV_MAPPER) { // We cannot determine what this is so we have to assume the worst, as the default // devive's volume control is irreparably broken. return true; } // The Microsoft GS Wavetable Synth advertises itself as MIDIDEV_SWSYNTH with a VOLUME control. // If the one we're using doesn't match that, we don't need to bother checking the name. if (caps.wTechnology == MIDIDEV_SWSYNTH && (caps.dwSupport & MIDICAPS_VOLUME)) { if (strncmp(caps.szPname, "Microsoft GS", 12) == 0) { return true; } } } return false; }
static void test_midiOut_device(UINT udev, HWND hwnd) { HMIDIOUT hm; MMRESULT rc; MIDIOUTCAPSA capsA; DWORD ovolume; UINT udevid; MIDIHDR mhdr; rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA)); ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (!rc) { trace("* %s: manufacturer=%d, product=%d, tech=%d, support=%X: %d voices, %d notes\n", capsA.szPname, capsA.wMid, capsA.wPid, capsA.wTechnology, capsA.dwSupport, capsA.wVoices, capsA.wNotes); ok(!((MIDIMAPPER==udev) ^ (MOD_MAPPER==capsA.wTechnology)), "technology %d on device %d\n", capsA.wTechnology, udev); if (MOD_MIDIPORT == capsA.wTechnology) { ok(capsA.wVoices == 0 && capsA.wNotes == 0, "external device with notes or voices\n"); ok(capsA.wChannelMask == 0xFFFF, "external device channel mask %x\n", capsA.wChannelMask); ok(!(capsA.dwSupport & (MIDICAPS_VOLUME|MIDICAPS_LRVOLUME|MIDICAPS_CACHE)), "external device support=%X\n", capsA.dwSupport); } } if (hwnd) rc = midiOutOpen(&hm, udev, (DWORD_PTR)hwnd, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); else rc = midiOutOpen(&hm, udev, (DWORD_PTR)callback_func, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); if (rc == MMSYSERR_NOTSUPPORTED) { skip( "MIDI out not supported\n" ); return; } ok(!rc, "midiOutOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return; test_notification(hwnd, "midiOutOpen", MOM_OPEN, 0); rc = midiOutGetVolume(hm, &ovolume); ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume rc=%s\n", mmsys_error(rc)); /* The native mapper responds with FFFFFFFF initially, * real devices with the volume GUI SW-synth settings. */ if (!rc) trace("Current volume %x on device %d\n", ovolume, udev); /* The W95 ESFM Synthesis device reports NOTENABLED although * GetVolume by handle works and music plays. */ rc = midiOutGetVolume(UlongToHandle(udev), &ovolume); ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR || broken(rc==MMSYSERR_NOTENABLED) : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume(dev=%d) rc=%s\n", udev, mmsys_error(rc)); rc = midiOutGetVolume(hm, NULL); ok(rc==MMSYSERR_INVALPARAM, "midiOutGetVolume NULL rc=%s\n", mmsys_error(rc)); /* Tests with midiOutSetvolume show that the midi mapper forwards * the value to the real device, but Get initially always reports * FFFFFFFF. Therefore, a Get+SetVolume pair with the mapper is * not adequate to restore the value prior to tests. */ if (winetest_interactive && (capsA.dwSupport & MIDICAPS_VOLUME)) { DWORD volume2 = (ovolume < 0x80000000) ? 0xC000C000 : 0x40004000; rc = midiOutSetVolume(hm, volume2); ok(!rc, "midiOutSetVolume rc=%s\n", mmsys_error(rc)); if (!rc) { DWORD volume3; rc = midiOutGetVolume(hm, &volume3); ok(!rc, "midiOutGetVolume new rc=%s\n", mmsys_error(rc)); if (!rc) trace("New volume %x on device %d\n", volume3, udev); todo_wine ok(volume2==volume3, "volume Set %x = Get %x\n", volume2, volume3); rc = midiOutSetVolume(hm, ovolume); ok(!rc, "midiOutSetVolume restore rc=%s\n", mmsys_error(rc)); } } rc = midiOutGetDevCapsA((UINT_PTR)hm, &capsA, sizeof(capsA)); ok(!rc, "midiOutGetDevCaps(dev=%d) by handle rc=%s\n", udev, mmsys_error(rc)); rc = midiInGetDevCapsA((UINT_PTR)hm, (LPMIDIINCAPSA)&capsA, sizeof(DWORD)); ok(rc==MMSYSERR_BADDEVICEID, "midiInGetDevCaps(dev=%d) by out handle rc=%s\n", udev, mmsys_error(rc)); { DWORD e = 0x006F4893; /* velocity, note (#69 would be 440Hz) channel */ trace("ShortMsg type %x\n", LOBYTE(LOWORD(e))); rc = midiOutShortMsg(hm, e); ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); if (!rc) Sleep(400); /* Hear note */ } memset(&mhdr, 0, sizeof(mhdr)); mhdr.dwFlags = 0; mhdr.dwUser = 0x56FA552C; mhdr.dwOffset = 0xDEADBEEF; mhdr.dwBufferLength = 70000; /* > 64KB! */ mhdr.lpData = HeapAlloc(GetProcessHeap(), 0 , mhdr.dwBufferLength); ok(mhdr.lpData!=NULL, "No %d bytes of memory!\n", mhdr.dwBufferLength); if (mhdr.lpData) { rc = midiOutLongMsg(hm, &mhdr, sizeof(mhdr)); ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER); rc = midiOutPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)-1); ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); rc = midiOutPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutPrepare old size rc=%s\n", mmsys_error(rc)); rc = midiOutPrepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); trace("MIDIHDR flags=%x when unsent\n", mhdr.dwFlags); HeapFree(GetProcessHeap(), 0, mhdr.lpData); } ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser); ok(mhdr.dwOffset==0xDEADBEEF, "MIDIHDR.dwOffset changed to %x\n", mhdr.dwOffset); rc = midiOutGetID(hm, &udevid); ok(!rc, "midiOutGetID rc=%s\n", mmsys_error(rc)); if(!rc) ok(udevid==udev, "midiOutGetID gives %d, expect %d\n", udevid, udev); rc = midiOutReset(hm); /* Quiet everything */ ok(!rc, "midiOutReset rc=%s\n", mmsys_error(rc)); rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiOutClose", MOM_CLOSE, 0); test_notification(hwnd, "midiOut over", 0, WHATEVER); }