How to play 2 different sounds at the same time?(Visual basic) - vb.net

I have a problem about a game. I want to play a background sound and another sound when you click a button. When this happens, the background sound stops and the 2nd sound starts. When the 2nd sound finishes, no sound will be played.
You can see my code below:
Imports System.Media.SoundPlayer
Public Class GamePlaying
Dim mainmenusndplayer As New System.Media.SoundPlayer
Private Sub GamePlaying_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
MainMenu.Show()
mainmenusndplayer.Stop()
End Sub
Private Sub btn_Fire_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Fire.Click
btn_Fire.Enabled = False
Dim shotsound As New System.Media.SoundPlayer
shotsound.Stream = My.Resources.TankShoot
shotsound.Play()
End Sub
Private Sub GamePlaying_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
mainmenusndplayer.Stream = My.Resources.WoT_Roll_Out
mainmenusndplayer.Load()
mainmenusndplayer.PlayLooping()
End Sub
End Class

I had been struggling with the same issue.....
The short answer is you can't. The system will only permit one channel to the sound interface within any given process. As such, when you start a new sound, the previous one terminates.
There are a number of work-arounds which mostly use either Direct-X or Media-Player. However, I found neither of those solutions to be either easy or robust in that you are depending on the users machine to have the right things installed.
However, I found a quick and simple solution to the problem.
I added a special "hook" to my application so that when I run it with an appropriate command line argument, all it does is play a particular sound and quit. I then use the process object to start another instance of the application with the appropriate argument.. and hey presto.. multiple sounds.
If your application is configured to automatically be be a single instance, you need to disable that and replace it with a little code to detect another instance and quit.
Another alternative is to add a small exe to your application package that simply does the sound part.
I know it does not sound very "pure", but really, all you are doing is starting a process to play a sound in the background. It doesn't really matter if that process is a windows native function or one of your own making.

you can use winmm.dll with mciSendString :
Imports System.Text
Imports System.Runtime.InteropServices
<DllImport("winmm.dll")>
Private Shared Function mciSendString(ByVal command As String, ByVal buffer As
StringBuilder, ByVal bufferSize As Integer, ByVal hwndCallback As IntPtr) As Integer
End Function
Private Sub MyForm_Click(sender As Object, e As EventArgs) Handles Me.Click
mciSendString("open " & Chr(34) & "C:\myFile1.wav" & Chr(34) " type waveaudio alias Sound1" & internalName, Nothing, 0, IntPtr.Zero)
mciSendString("open " & Chr(34) & "C:\myFile2.wav" & Chr(34) " type waveaudio alias Sound2" & internalName, Nothing, 0, IntPtr.Zero)
mciSendString("play Sound1", Nothing, 0, Me.Handle.ToInt64())
mciSendString("play Sound2", Nothing, 0, Me.Handle.ToInt64())
mciSendString("setaudio Sound1 volume to 1000", Nothing, 0, Me.Handle.ToInt64())
mciSendString("setaudio Sound2 volume to 1000", Nothing, 0, Me.Handle.ToInt64())
End Sub
and to stop the sounds you have to :
mciSendString("close Name1", Nothing, 0, Me.Handle.ToInt64())
mciSendString("close Name2", Nothing, 0, Me.Handle.ToInt64())
Download winmm.dll at https://www.dll-files.com/winmm.dll.html

Related

Global hotkey not registered in game using GetAsyncKeyState - vb.net

I've made a tool that will continuously click for the user if they decide to have it on with toggle keys etc, it all works fine in ordinary windows e.g google chrome, but when it comes to games it doesn't always work correctly.
(well it does in some games, then others it doesn't)
The code is designed to click fast while holding LButton, then stop when it's let go to act as an autoclicker (user has control of speed) which again works, but when in a game it clicks alot slower than it's suppose to / any other window / app.
I've figured out adding a delay using
Thread.Sleep(200)
fixes the speed of the autoclicker in game, but then it messes up the keybind which results in the autoclicker always clicking even when LButton isnt held / pressed.
Is there anything else that I could use as a delay, or anything else I can do to the code so it works correctly?
I've been trying many different variations and searching online the last few days trying to get it working, but none succeeded.
Here's all the code got to do with autoclicking in my project, i've added some notes to try and explain which part is doing what / speeds the timers are set to.
Imports System.Threading
Public Class Form1
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vkey As Integer) As Short
Private Declare Sub mouse_event Lib "user32" (ByVal dwflags As Integer, ByVal dx As Integer, ByVal cbuttons As Integer, ByVal dy As Integer, ByVal dwExtraInfo As Integer)
Private Const mouseclickup = 4
Private Const mouseclickdown = 2
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Timer1 isnt doing the clicking, Timer1 is just listening for LButton
'clicks which is why I have it always on aswell as a low interval.
Timer1.Start()
Timer1.Interval = 1
'LButton is the timer that will do the clicking.
LButton.Interval = 100
End Sub
Private Sub LButton_Tick(sender As Object, e As EventArgs) Handles LButton.Tick
If GetAsyncKeyState(Keys.LButton) Then
mouse_event(mouseclickup, 0, 0, 0, 0)
'Without Thread.Sleep(200) the code works as it's suppose to, clicks
'when LButton is held, stops clicking when LButton is let go,
'although without Thread.Sleep(200) it will not work in all games,
'but with it, it will continuously click even when LButton isn't held.
Thread.Sleep(200)
mouse_event(mouseclickdown, 0, 0, 0, 0)
Else
LButton.Stop()
End If
End Sub
Private Sub Timer1_Tick_1(sender As Object, e As EventArgs) Handles Timer1.Tick
'This is what will listen for the left clicks and also stop the left
'LButton timer if LButton is not held
If GetAsyncKeyState(Keys.LButton) Then
LButton.Start()
Else
LButton.Stop()
End If
End Sub
End Class
Quoting the MSDN documentation, GetAsyncKeyState() determines:
whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.
So when you check the function via If GetAsyncKeyState(Keys.LButton) Then, it will return non-zero at least three times, thus execute the code more than you want (which is what you experience when you add Thread.Sleep(200)).
To check if the key is held down you have to check if the most significant bit is set, which for a Short is 0x8000 in hex and 32768 in decimal.
Checking a bit flag is done by checking (<number> And <bit>) = <bit> - where And is the bitwise And operator.
This would result in your code looking like this:
Const KeyDownBit As Integer = &H8000
Private Sub LButton_Tick(sender As Object, e As EventArgs) Handles LButton.Tick
If (GetAsyncKeyState(Keys.LButton) And KeyDownBit) = KeyDownBit Then
mouse_event(mouseclickup, 0, 0, 0, 0)
Thread.Sleep(200)
mouse_event(mouseclickdown, 0, 0, 0, 0)
Else
LButton.Stop()
End If
End Sub
Private Sub Timer1_Tick_1(sender As Object, e As EventArgs) Handles Timer1.Tick
If (GetAsyncKeyState(Keys.LButton) And KeyDownBit) = KeyDownBit Then
LButton.Start()
Else
LButton.Stop()
End If
End Sub
I'm not sure whether your second timer (Timer1) is actually needed in this case.

Determine if process is done?

Background
I am trying to think of how to logically tell if a process is complete. I currently have a separate program that generates a text file with then name "Information" for its title bar. When the information text file appears, the program is dumping a whole bunch of data to it. This can take a few seconds or many depending on the data. Basically I am trying to think of the best way for me to tell when that file is done being written to. Keep in mind that when I say text file, it is not the same as notepad as it does not have a physical file location. It is merely a part of the program that generates it.
Here is what I have so far:
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
End Function
Dim proc As Integer
Do Until proc <> 0
proc = FindWindow(vbNullString, "Information")
Loop
I was thinking that I could possibly use the process ID and determine how much of the CPU it is using.. if it is high then the process is currently in use, and if low then it is done. The above code has no problem finding the process.
Is this a good approach to tell if it is done? If so, how do I determine CPU usage based on a process ID? There may be a better method than I am thinking of.
Process[] processes = Process.GetProcessesByName("ProcessName")
process = processes[0]
process.WaitForExit()
But that will freeze program until process it's done.
So incorporating background worker as Ayush said.
Private Sub StartButton_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles StartButton.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker1.DoWork
Process[] processes = Process.GetProcessesByName("ProcessName")
process = processes[0]
process.WaitForExit()
"you can put some code here for when it's done or below method.
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
Handles BackgroundWorker1.RunWorkerCompleted
"this will get called when bw done
End Sub
You can use the BackgroundWorker control in Visual Basic, it has an event called "Run Worker Completed" which will be raised when the task is successful, failed or cancelled.

Audio Recorder - Select Recording Device - VB.Net

I'm trying to create an audio recorder using VB.Net.
This is how I'm doing it:
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
mciSendString("open new Type waveaudio Alias recsound", "", 0, 0)
mciSendString("set recsound samplespersec 11025 channels 2 bitspersample 16 alignment 4 bytespersec 44100", vbNullString, 0, 0)
mciSendString("record capture", vbNullString, 0, 0)
Label1.Text = "Recording..."
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
mciSendString("save recsound c:\recsound.wav", "", 0, 0)
mciSendString("close recsound", "", 0, 0)
Label1.Text = "Stopped."
End Sub
It works fine, the only problem is that I have two mics, one of them is built-in and the other one is connected via USB. The second one has a way better recording quality but this application always records from the built-in mic.
I've searched all over the internet and I can't find a way to select the recording device. The only thing I was able to find was:
Dim DeviceId As Integer = 2
mciSendString("set recsound input " & DeviceId.ToString())
I've tried different values to no avail.
I have also tried the following code that successfully listed all the properties of all the recording devices found in my computer but I couldn't find anything that could help:
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim objSearcher As New System.Management.ManagementObjectSearcher("SELECT * FROM Win32_SoundDevice")
Dim objCollection As System.Management.ManagementObjectCollection = objSearcher.Get()
Me.TextBox1.Text = ""
For Each obj As ManagementObject In objCollection
Me.TextBox1.Text &= "---------------------------------" & vbCrLf
For Each myProperty As PropertyData In obj.Properties
Me.TextBox1.Text &= myProperty.Name & " - " & myProperty.Value & vbCrLf
Next
Next
End Sub
Any suggestions will be appreciated.
I realize that you asked this question almost two years ago and so you may never see this answer. Perhaps you have notifications turned on and this may help you.
I have switched to Naudio (available through Nuget) for my recording applications and have had much better luck with it. I can specify the recording device as follows:
waveIn = New WaveIn
waveIn.DeviceNumber = 0 '0 - Stereo Mix, 1 - Microphone, 2 - Line In
Figure out what device number your USB microphone is and use that. Do a search on "Naudio" and you will find example code.

VB.NET backgroundworker from a second module

frmMain has a button that kicks off a background worker
Private Sub btnProcessITN_Click(sender As Object, e As EventArgs) Handles btnProcessITN.Click
Me.frmMainProgressBar.Visible = True
Me.btnProcessITN.Text = "working..." & Me.frmMainProgressBar.Value & "%"
Me.btnProcessITN.Enabled = False
backgroundWorker2.WorkerReportsProgress = True
BackgroundWorker2.RunWorkerAsync()
End Sub
Private Sub backgroundWorker2_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork
ProcessITN()
End Sub
ProcessITN lives in modITN. This runs, does its thing, then PROBLEM
Public Sub ProcessITN()
...doing work here....
frmMain.updateProgress(current, Max)
End Sub
and back in form main I have a function that tries to update the progress of the background worker, and update a progress bar on the form
Public Function updateProgress(current As Integer, Max As Integer) As Boolean
BackgroundWorker2.ReportProgress((current / Max) * 100)
Return True
End Function
Private Sub backgroundWorker2_ProgressChanged( _
ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) _ Handles BackgroundWorker2.ProgressChanged
Me.frmMainProgressBar.Value = e.ProgressPercentage
Me.btnProcessITN.Text = "working..." & Me.frmMainProgressBar.Value & "%"
'Me.txtProgress.Text = Me.txtProgress.Text & vbNewLine & strMessage
Me.txtProgress.AppendText(vbNewLine & strMessage)
End Sub
Now, the problem is, that although the code is running, and the values are being passed across correctly from modITN to frmMain, the form itself is not refreshing. the progress bar does not change. txtProgress does not change.
N.B this code was working perfectly when the stuff within modITN was within frmMain. I moved it to try and tidy my code.
You may still have a look here, I had the same question - and there are some more issues to it.
Multithreading for a progressbar and code locations (vb.net)?
VB.net's 'Default Instance' of Forms is a hideous trap in my opinion.
I've sorted the problem!
I moved the backgroundworker blocks to modITN, out frmMain. The whole thing runs in modITN now, and updates the progress bar from there. frmMain simply calls the sub in modITN to start the whole thing off.
Simple!

Sending SMS via USB GSM Modem

I am trying to develop a module to send SMS from my application. The problem is that when I send an AT Command to a connected cell phone, my app stops responding. I'm using a Nokia 6720C and I have installed Pc Suite. It also appears in the Com Ports.
My code is below. What am I doing wrong?
Imports System
Imports System.IO.Ports
Imports System.Threading
Imports System.ComponentModel
Public Class Form1
Delegate Sub SetTextCallback(ByVal [text] As String)
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
With SerialPort1
.PortName = "COM14"
.DataBits = 8
.Parity = IO.Ports.Parity.None
.StopBits = StopBits.One
End With
SerialPort1.Open()
SerialPort1.Write("AT" & vbCr)
SerialPort1.Close()
End Sub
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
ReceivedText(SerialPort1.ReadExisting())
End Sub
Private Sub ReceivedText(ByVal [text] As String)
'compares the ID of the creating Thread to the ID of the calling Thread
If Me.TxtResponse.InvokeRequired Then
Dim x As New SetTextCallback(AddressOf ReceivedText)
Me.Invoke(x, New Object() {(text)})
Else
Me.TxtResponse.Text &= [text]
End If
End Sub
Well, at the end of the AT command you must add Chr(13) and Chr(10), you used Chr(13) only (which is "vbCr"), try replacing it with vbCrLf (Carriage-Return "Chr(13)" and Line Feed "Chr(10)"). I think this is the problem (the command string is not complete).
If the problem still resides, try the following to test your work:
Try using your VB.NET code to communicate with a GSM modem (not your phone). If it works fine, then maybe the phone does not accept AT commands.
Try using a terminal program to send the AT command to the phone. The terminal program can be like "Hyper Terminal" or "Maestro Smart Terminal" (you can search for it on google).
I hope this was helpful, good luck.