Hi,
I have some problem by using the midi file. I wish to control the left and the right channels volumes, and i got some information from msdn library, but it didn't tell me the exact way to do it. Could anyone tell me what is the meaning of

"The low-order word contains the left-channel volume setting, and the high-order word contains the right-channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence."

The sentence above i copy from the the msdn library of MidiOutGetVolume and midiOutSetVolume. Does it mean the low order is 0x000 to 0x7777(left channel) and 0x8000 to 0xFFFF is high order (right channel)?

The code below is modified from an example from internet. Although I set the midiOutSetVolume(hdev, 0xF000); But it didn't work at all.

Anyone have similar example could control the left and right volumes? I already stuck on this step quite a while.

I wish someone could give some suggestion for me. Thanks a lot.

#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "Winmm.lib")
#define NOTE_ON 0x90
#define NOTE_OFF 0x80

//command, note, velocity
#define MAKE_MSG(X, Y, Z) (X + (Y<<8) + (Z<<16))

int playChord(HMIDIOUT hdev)
{
       [B]midiOutSetVolume(hdev, 0x0000);[/B]
       midiOutShortMsg(hdev, MAKE_MSG(NOTE_ON, 62, 65));
       Sleep(1000);
       [B]midiOutSetVolume(hdev, 0xF000);
[/B]       midiOutShortMsg(hdev, MAKE_MSG(NOTE_ON, 62, 65));
       Sleep(1000);
       [B]midiOutSetVolume(hdev, 0x5555);
[/B]       midiOutShortMsg(hdev, MAKE_MSG(NOTE_ON, 62, 65));
       Sleep(1000);
       [B]midiOutSetVolume(hdev, 0xFFF0);
[/B]       midiOutShortMsg(hdev, MAKE_MSG(NOTE_ON, 62, 65));

       Sleep(1000);

       midiOutShortMsg(hdev, MAKE_MSG(NOTE_OFF, 62, 65));
       midiOutShortMsg(hdev, MAKE_MSG(NOTE_OFF, 62, 65));
       midiOutShortMsg(hdev, MAKE_MSG(NOTE_OFF, 62, 65));
       midiOutShortMsg(hdev, MAKE_MSG(NOTE_OFF, 62, 65));

       return 0;
}

int main()
{
       HMIDIOUT hdev;
       static MIDIOUTCAPS devCaps;
       static LPMIDIOUTCAPS lpCaps = &devCaps;
       DWORD abc;

[B]       devCaps.dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;[/B]

       abc = devCaps.dwSupport;
       if (devCaps.dwSupport == MIDICAPS_VOLUME|MIDICAPS_LRVOLUME)
       {
              wprintf(L"abc");
       }

       midiOutGetDevCaps(0, lpCaps, sizeof(MIDIOUTCAPS)); // Get device capabilities for first device (curDevice == 0)
       midiOutOpen(&hdev, -1, NULL, NULL, CALLBACK_NULL);

       midiOutSetVolume(hdev, 0x0000);

       wchar_t menu_sel = 0;

       while(menu_sel != 'q')
       {
              wprintf(L"Midi test app\nc: play chord\nd: change device\nv: set volume\nq: quit\n");
              wscanf(L" %c", &menu_sel);

              switch(menu_sel)
              {
              case 'q':
                     break;
              case 'c':
                     playChord(hdev);
                     break;
              default:
                     wprintf(L"try again\n");
                     break;
              }
       }
       midiOutClose(hdev);

       return 0;
}

Recommended Answers

All 3 Replies

A WORD is 16 bits. So both the right and left channels have a range from 0x0000 to 0xFFFF. To make a DWORD, you have to use the MAKELONG macro.

WORD leftChannel = 0x0010 ;
WORD rightChannel = 0x00FF ;

Do

DWORD bothChannels= MAKELONG ( leftChannel , rightChannel );

and pass bothChannels to midiOutSetVolume( hdev, bothChannels) But the actual device may not support all 16 bits that can be set for a channel.

It may help if you post the location of the original example.

Better keep an eye on this too.

hi thank you for your reply, and i tried to do your's way, which is combined the left and right channels value and passed it to setvolume, but it didn't work.

I tried another way also. By high and low order it's referring to packaging two words together to form a single 32-bit integer. That is, 0xFFFFFFFF is both channels full volume, 0xFFFF0000 is right channel full on and left channel off, 0x80008000 is both channels at half-way and 0x00008000 is left channel at half-way. But it didn't woork as well.


The text below i copied from midioutsetvolume msdn library. I think i understand the first paragraph. But i'm not really understand the paragraph 2 and 3. Could you give me some suggestion?
http://msdn2.microsoft.com/en-us/library/ms711639.aspx

"You can also determine whether the device supports volume control on both the left and right channels by querying the device using the midiOutGetDevCaps function and the MIDICAPS_LRVOLUME flag.

Devices that do not support a full 16 bits of volume-level control use the high-order bits of the requested volume setting. For example, a device that supports 4 bits of volume control produces the same volume setting for the following volume-level values: 0x4000, 0x43be, and 0x4fff. The midiOutGetVolume function returns the full 16-bit value, as set by midiOutSetVolume, irrespective of the device's capabilities.

Volume settings are interpreted logarithmically. This means that the perceived increase in volume is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000."

Well, looking at the documentation for midiOutSetVolume, I see that there is a

MMSYSERR_NOTSUPPORTED The function is not supported.

error value that can be returned when using that function. So maybe that is the reason in your case also. But the only way is to check the return value of midiOutSetVolume.

Use the following piece of code for that.

MMRESULT  res =  midiOutSetVolume( hdev, 0x0000) ;
    wprintf( L"midiOutSetVolume: " );
    switch ( res )
    {
    case MMSYSERR_INVALHANDLE: 
        wprintf( L"The specified device handle is invalid.\n" ); 
        break;

    case MMSYSERR_NOMEM:     
        wprintf( L"The system is unable to allocate or lock memory.\n"); 
        break;

    case MMSYSERR_NOTSUPPORTED:     
        wprintf( L"The function is not supported.\n" ); 
        break;
    case MMSYSERR_NOERROR:
        wprintf( L"success.\n" ); 
        break;

    default:
        wprintf( L"Undocumented Return value.\n" ); 
        break;
    }

If the function is not supported, I don't think there is anything you can do about that...(Not sure though) Anyone who has a better idea please answer.

Anyway remember to check return values when you use an API function. Return values are there for a reason.

Also, I don't see the reason for this piece of code.

DWORD abc;

       devCaps.dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;

       abc = devCaps.dwSupport;
       if (devCaps.dwSupport == MIDICAPS_VOLUME|MIDICAPS_LRVOLUME)
       {
              wprintf(L"abc");
       }

You should check the value of devCaps.dwSupport after the call to midiOutGetDevCaps .

midiOutGetDevCaps(0, lpCaps, sizeof(MIDIOUTCAPS)); 

       if (devCaps.dwSupport == ( MIDICAPS_VOLUME|MIDICAPS_LRVOLUME ) )
       {
              wprintf(L"Left and Right Volumes Supported\n");
       }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.