none
waveOut control handle not device

    Question

  • Public Class AudioProfile Declare Function waveOutOpen Lib "winmm.dll" (ByRef hwo As IntPtr, ByVal uDeviceID As Integer, ByRef pwfx As WAVEFORMATEXTENSIBLE, ByVal dwCallback As WaveOutCallback, _ ByVal dwCallbackInstance As Integer, ByVal dwFlags As Integer) As Integer Declare Function waveOutSetVolume Lib "winmm.dll" (ByVal hwo As IntPtr, ByVal dwVolume As UInteger) As Integer Public Shared out_ptrCallback As New WaveOutCallback(AddressOf Form1.WaveOut_CallBack) Dim hwaveOut as Intptr End Class Public Class Form1 Private BufferWaveOutIntptr as New List(Of Intptr) Dim Volume As Integer Dim volume_msg as UInteger Dim Left as integer = 0 Private SplPerSec As Integer = 44100 Private SplBits As Integer = 16 Private SCO(66) As Integer 'this list is the sound cards'

    Public playFunction() For S = 0 to 1

    BufferWaveOutIntptr.Add(S) Dim wFormatE As AudioProfile.WAVEFORMATEXTENSIBLE wFormatE.wFormatTag = AudioProfile.WFORMATS.EXTENSIBLE wFormatE.nChannels = 2 wFormatE.nSamplesPerSec = SplPerSec Dim adjustBits As Integer If SplBits > 16 And SplBits < 24 Then adjustBits = 24 Else adjustBits = SplBits End If wFormatE.dwBitsPerSample = adjustBits wFormatE.Samples.wValidBitsPerSample = SplBits wFormatE.nBlockAlign = wFormatE.nChannels * (wFormatE.dwBitsPerSample / 8) wFormatE.nAvgBytesPerSec = wFormatE.nBlockAlign * wFormatE.nSamplesPerSec wFormatE.cbSize = 22 wFormatE.dwChannelMask = AudioProfile.SpeakerFlagshex.SPEAKER_FRONT_LEFT + AudioProfile.SpeakerFlagshex.SPEAKER_FRONT_RIGHT wFormatE.SubFormat = AudioProfile.KSDATAFORMAT_SUBTYPE_PCM ' not going to put all the structures and enums for the formats here. that all seems correct.' Dim NF As AudioProfile.WAVEHDR NF.lpData = 'this data is created in a function and passed here' NF.dwBufferLength = 'this data is compile in a function and passed here' NF.dwBytesRecorded = 0 NF.dwUser = 0 NF.dwFlags = 0

    'this is an attempt to control the instance from the handle. it is occurring to the instance

    that is on this particular sound device, but I thought the handle would control the instance and not

    the sound card. I am actually building a Intptr list and not just one instance. It plays all the

    waves and can keep track of their handles duration this way, but not control volume separately. It

    wants to adjust all instances at once. Is it possible to adjust them separately with this DLL?'

    AudioProfile.waveOutOpen(BufferWaveOutIntptr(S), SCO(S), wFormatE, AudioProfile.out_ptrCallback, Nothing, AudioProfile.CallBacks.CALLBACK_FUNCTION) AudioProfile.waveOutPrepareHeader(BufferWaveOutIntptr(S), NF, Marshal.SizeOf(NF)) AudioProfile.waveOutWrite(BufferWaveOutIntptr(S), NF, Marshal.SizeOf(NF)) Next End Function

    Public Sub Button1() Volume +=1 volume_msg = ("&H" & Hex(Volume) & left.ToString("0000")) AudioProfile.waveOutSetVolume(AudioProfile.hwaveOut, volume_msg) End Sub Public Sub Button2() Volume -=1 volume_msg = ("&H" & Hex(Volume) & left.ToString("0000")) AudioProfile.waveOutSetVolume(AudioProfile.hwaveOut, volume_msg) End Sub Public Function WaveOut_CallBack(ByVal hwo As Integer, ByVal uMsg As UInteger, ByVal dwInstance As Integer, ByVal dwParam1 As Integer, ByVal dwParam2 As Integer) As Integer Select Case uMsg Case AudioProfile.MM_WOM.MM_WOM_DONE Case AudioProfile.MM_WOM.MM_WOM_CLOSE Case AudioProfile.MM_WOM.MM_WOM_OPEN

    'this removes the intptr address of 0 and then replaces it with the callback ID. This works.

    I tried to explain this. I have done this differently as well. I generate a number in the play function that is

    unique instead of using the number 0 to start and it passes through here if I do this. Then I dont

    remove it here and just skip the callback ID. That works too. When I do this, I remove and insert the numbers

    in the play function.'

    For S = 0 to BufferWaveOutIntptr.Count-1

    BufferWaveUutIntptr.RemoveAt(0)

    if BufferWaveOutIntptr.Count > 0 then

    BufferWaveOutIntptr.Insert(S,hwo)

    else

    BufferWaveOutIntptr.Add(Hwo)

    end if

    Next End Select Return Nothing End Function End Class


     Guys,

     Still having issues.  I am not sure I am controlling the handle instead of the device.







     












    • Edited by -tE Friday, March 09, 2018 4:43 PM
    Friday, March 09, 2018 12:03 AM

Answers

  • I am able to pan.  You have to send it change volume for each side of the sound card.  In the high/low format of FFFF0000 or 0000FFFF.

    That panning is simply left to right and doesn't require you to address each channel - just a stereo device.   If you comment your code it might be possible to see what you are intending to do, because it isn't obvious.  It seems that you are opening one device with two channels: in that case control of the channels isn't required and you should be using an ID not a handle.  If you aren't panning between channels, then what is the problem?  Is it that you can't stream selected audio to a specific channel - that's what you imply when you say "They both work,  but are not specific to the wave".  But that's not what your code does.

    • Marked as answer by -tE Monday, March 12, 2018 9:30 PM
    Friday, March 09, 2018 6:19 AM

All replies

  •  I would HIGHLY recommend that you turn Option Strict on because you are making a lot of Type Conversion errors in your code.  For example,  you are declaring 'volume_msg' as a Double type which is wrong to start with,  it should be a UInteger type.  Next,  you are assigning a String type to that Double type which is wrong and should not be done.  Then you are passing that Double type to the second parameter of the waveOutSetVolume function which is expecting a UInteger type value to be passed to it.

     As I have said in your last few questions,  you really need to understand the difference between the data types.  If you just use any old data type wherever you want,  you will wind up with all kinds of unexpected results and/or exceptions which can be very difficult to find.  Turning Option Strict on will highlight these errors in your code that need to be fixed correctly.

     Below is the same example I posted a link to in your last question but,  this has volume control added to it.  Perhaps it will help you get your code for controlling the volume corrected the way it should be.

     Wave Player Example (With Volume Control)

     Also,  there is no need to get the handle to the device using the callback,  it is already returned to the 'AudioProfile.hwaveOut' when you call the waveOutOpen function.

     However,  with much testing over the years,  I have never been able to set the volume of just one or the other wave file using these methods if that is what you want to do.  Even though I have experimented and played 2 separate files on the same device and have different handles for the two,  it seems that they must point to the same device.  I say this because if I set the volume of one by using it's handle,  it sets the volume for both of the files I am playing through that device.

     Perhaps someone else can explain how it can be done if they have actually tried it and know it works.  Perhaps I have missed something stupid all these years but,  I don't think it works this way unless you actually have separate devices,  like two separate sound cards.  Maybe Reed can give some info on this?

     As Reed had said a few questions back,  I believe you can control the volumes separately by using DirextX and creating a new SecondaryBuffer for each wave file.


    If you say it can`t be done then i`ll try it

    Friday, March 09, 2018 2:44 AM
  • IR,

       I am aware there must be and are syntax issues.  But my concern is functionality.  After all the advice and sharing,  are we going to find that the device is the only controllable format with this dll?  That's the first point that has to be addressed.  I have to be able to control the instance and not the actual device.  The literature seems to make a point that I should be able to. 

    I change the reference of my volume tag,  and yes it will pass now as a Uint.  It wasn't, but you guys pointed out that I needed to work on a way to pass values lower than 4096.  It works as a uint which is what the call asks for.

    I am trying the best to write without an outside vender,  but just might not be able to.  There are a few choices,  but would rather not.

    Friday, March 09, 2018 3:16 AM
  • IR,

       After all the advice and sharing,  are we going to find that the device is the only controllable format with this dll?

     I am not sure.  This is why I suggested that maybe someone who has actually done it using the Wave Functions may be able to help.  However,  as I said,  I could never get it to work by calling the waveOutOpen function twice to get two separate handles and passing one or the other to the waveOutSetVolume function.  It always changed the volume of both.

     So,  lets see what else others may have to say.  8)


    If you say it can`t be done then i`ll try it

    Friday, March 09, 2018 3:30 AM
  •  Still having issues.  I am not sure I am controlling the handle instead of the device.

    After you have fixed the data type problems you need to describe what you are trying to do.   Code that isn't working is not a good way to describe what you are trying to achieve.  For instance, you are using the return value from the open function for the handle in the set volume method call, but your open flags are indicating that the handle will be provided in the callback!  It seems inconsistent.  Add a comment to each line so people can see what you expect to happen, and it might be possible to indicate why that isn't happening.

    Friday, March 09, 2018 3:37 AM
  • FYI I dynamically created two instances of WindowsMediaPlayer object and could set the volume differently using slider controls in both as both were playing different .Wav files. However setting Balance (-100 to 100) using slider controls does not do anything at all for either instance.

    The actual Windows Media Player application however seems to have no Balance available. And it appears to be a single instance application.

    Perhaps if all you want is the ability to play two .Wav files simultaneously changing the volume of either then it is possible with the WMP object. Add ref, Com, WMPLib.

    Maybe you should look into WASAPI. Also see Windows Audio Architecture although about Win10 it has list of deprecated and recommended API's and see Recording and playing PCM audio on Windows 8 (VB) which seems to have information for Pinvokes necessary to use WASAPI for recording and playing. Also note from one of the links that IChannelAudioVolume - Enables a client to control the volume levels for all of the channels in the audio session that the stream belongs to and SetChannelVolume - Sets the volume level for the specified channel in the audio stream if any of that is helpful.


    La vida loca


    Friday, March 09, 2018 4:38 AM
  •  Still having issues.  I am not sure I am controlling the handle instead of the device.

    After you have fixed the data type problems you need to describe what you are trying to do.   Code that isn't working is not a good way to describe what you are trying to achieve.  For instance, you are using the return value from the open function for the handle in the set volume method call, but your open flags are indicating that the handle will be provided in the callback!  It seems inconsistent.  Add a comment to each line so people can see what you expect to happen, and it might be possible to indicate why that isn't happening.

    I have fixed most of the syntax. 

    I am trying to simply pan 2 wave forms opposite each other through the same sound card.  The handle is passed after getting the address yes, from the callback.  I have also done the same thing by just giving it a random ID.  They both work,  but are not specific to the wave when it comes to the setVolume command.  MonkeyBoy said he found the same thing.  It might not be possible with the winmm dll.  Should be though.  If you have not worked with an audio DAW you might not understand.  There can be numerous wav files as well as numerous out/in devices.  They work by panning the file to the correct side of the stereo output.

    If the Intptr is not declared,  then the open declares it.  I am just referencing that ID. Yes?


    • Edited by -tE Friday, March 09, 2018 6:01 AM
    Friday, March 09, 2018 5:54 AM
  • FYI I dynamically created two instances of WindowsMediaPlayer object and could set the volume differently using slider controls in both as both were playing different .Wav files. However setting Balance (-100 to 100) using slider controls does not do anything at all for either instance.

    The actual Windows Media Player application however seems to have no Balance available. And it appears to be a single instance application.

    Perhaps if all you want is the ability to play two .Wav files simultaneously changing the volume of either then it is possible with the WMP object. Add ref, Com, WMPLib.

    Maybe you should look into WASAPI. Also see Windows Audio Architecture although about Win10 it has list of deprecated and recommended API's and see Recording and playing PCM audio on Windows 8 (VB) which seems to have information for Pinvokes necessary to use WASAPI for recording and playing. Also note from one of the links that IChannelAudioVolume - Enables a client to control the volume levels for all of the channels in the audio session that the stream belongs to and SetChannelVolume - Sets the volume level for the specified channel in the audio stream if any of that is helpful.


    La vida loca


    I am able to pan.  You have to send it change volume for each side of the sound card.  In the high/low format of FFFF0000 or 0000FFFF.

    I am aware of the newer WASAPI,  but am exhausting this dll first.

    • Edited by -tE Friday, March 09, 2018 5:57 AM
    Friday, March 09, 2018 5:55 AM
  • I am able to pan.  You have to send it change volume for each side of the sound card.  In the high/low format of FFFF0000 or 0000FFFF.

    That panning is simply left to right and doesn't require you to address each channel - just a stereo device.   If you comment your code it might be possible to see what you are intending to do, because it isn't obvious.  It seems that you are opening one device with two channels: in that case control of the channels isn't required and you should be using an ID not a handle.  If you aren't panning between channels, then what is the problem?  Is it that you can't stream selected audio to a specific channel - that's what you imply when you say "They both work,  but are not specific to the wave".  But that's not what your code does.

    • Marked as answer by -tE Monday, March 12, 2018 9:30 PM
    Friday, March 09, 2018 6:19 AM
  • I am able to pan.  You have to send it change volume for each side of the sound card.  In the high/low format of FFFF0000 or 0000FFFF.

    That panning is simply left to right and doesn't require you to address each channel - just a stereo device.   If you comment your code it might be possible to see what you are intending to do, because it isn't obvious.  It seems that you are opening one device with two channels: in that case control of the channels isn't required and you should be using an ID not a handle.  If you aren't panning between channels, then what is the problem?  Is it that you can't stream selected audio to a specific channel - that's what you imply when you say "They both work,  but are not specific to the wave".  But that's not what your code does.

    Yes.  The handle does not seem to point to the instance on this function.  The handle points to the sound device attached to the handles instance.  That's silly.  This doesn't seem to be what they had in mind

    PS.  I added some notes and a loop.  This is a smaller look at what the app is doing.

    • Edited by -tE Friday, March 09, 2018 4:40 PM
    Friday, March 09, 2018 2:41 PM