简体   繁体   中英

Gradually Increase System Volume on Windows Mobile / Windows CE 6.0

I'm attempting to use waveOutSetVolume from coredll.dll to gradually increase the audio volume from silent (or near silent) to maximum.

Most of the code examples I'm finding show some predefined set points for Off, Low, Normal, Medium, High, and Very High like this:

Public Enum Volumes As Integer
    OFF = 0
    LOW = 858993459
    NORMAL = 1717986918
    MEDIUM = -1717986919
    HIGH = -858993460
    VERY_HIGH = -1
End Enum

In my attempts, I tried raising the volume incrementally from 0 using 1200 as my increaser. This only increases the volume on the right channel. Somewhere around 66000 all the audio goes back to silent and begins increasing again, but only on the right channel.

The constants listed above do affect both channels as I hoped or expected. But It's not clear to me how to transition from 0 to 858993459 gradually, and then again from 858993459 to 1717986918 gradually, etc.

I suspect there's something fundamentally I'm not understanding about how this works.

I'm using VB.Net with .Net Compact Framework 3.5 in Visual Studio 2008. If you have a solution in C# I'm OK with that.

Edit:
From what I read now, the enum values listed above are based on Hex where 00000000 is the lowest possible volume and FFFFFFFF is the highest possible volume. That still doesn't help me a whole lot because I'm not sure how to gradually increase hex in VB.Net and Convert it to Integer at the same time. It's also unclear to me if merely increasing Hex here would cause the volume to increase on all/both channels at the same time or if I'd still have the stereo problem I'm having.

I'm using this class:

Public Class VolumeControl
    <DllImport("coredll.dll", SetLastError:=True)> _
    Friend Shared Function waveOutSetVolume(ByVal device As IntPtr, ByVal volume As Integer) As Integer
    End Function

    <DllImport("coredll.dll", SetLastError:=True)> _
    Friend Shared Function waveOutGetVolume(ByVal device As IntPtr, ByRef volume As Integer) As Integer
    End Function

    Public Shared Property Volume() As Integer
        Get
            Dim v As Integer = CInt(0)
            waveOutGetVolume(IntPtr.Zero, v)
            Return v
        End Get
        Set(ByVal value As Integer)
            waveOutSetVolume(IntPtr.Zero, value)
        End Set
    End Property
End Class

OK, and here's some API documentation which doesn't make a lot of sense to me in this particular context. What is low-order word and high-order word and how can they both exist in a single value?

· dwVolume
New volume setting. 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. If a device does not support both left and right volume control, the low-order word of dwVolume specifies the volume level, and the high-order word is ignored.

First, let me apologize slightly in that I'm going to answer in C#. It's too early and I've had no coffee, so my mental translator for VB isn't fired up yet.

The enum values look way better and way easier to understand in hex.

Public Enum Volumes As Integer  
    OFF = &H00000000  
    LOW = &H33333333
    NORMAL = &H66666666  
    MEDIUM = &H99999999  
    HIGH = &HCCCCCCCC  
    VERY_HIGH = &HFFFFFFFF  
End Enum  

So the volume is a DWORD, whiich maps to a 32-bit integer. So here's full volume:

0xFFFFFFFF

This is "split" into to WORD (16-bit) channels - left and right - conceptually like this:

0xFFFF 0xFFFF

Obviously the left channels have higher "place values", so to combine them it really looks like this:

0xFFFF0000 [left] && 0x0000FFFF [right] == 0xffffffff

If you had a low, non-zero value in a single change, say 0x0099, then the stero value would look like this:

0x00990099

So to continually raise both channel by the same amount, you'd loop from zero to ushort.MaxValue (0xffff), setting both WORDS (16-bit ushorts) in the DWORD (32-bit uint) to the same value:

UInt16 left;
UInt16 right;
UInt32 both;

for(int i = 0 ; i < ushort.MaxValue ; i++)
{
    left = i << 16; // left shift it to the upper 16 bits
    right = i;
    both = left & right;
    waveOutSetVolue(both);
    Thread.Sleep(10);
}

Obviously you'll want to adjust the Sleep pause and maybe the step that i increments by to get the effect you want. It's also often not a linear progression, so simply incrementing i might need to be more complex, but you get the idea.

EDIT1

Now that I've had coffee:

Dim left As UInt16
Dim right As UInt16
Dim both As UInt32

For i As Integer = 0 To UShort.MaxValue - 1
    ' left shift it to the upper 16 bits
    left = i << 16  
    right = i
    both = left And right
    waveOutSetVolue(both)
    Thread.Sleep(10)
Next

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM