2

I have this code in my .bat script.

( echo Set Sound = CreateObject("WMPlayer.OCX.7"^)
  echo Sound.URL = "music\sia.mp3"
  echo Sound.settings.volume = %volume%
  echo Sound.settings.setMode "loop", True
  echo Sound.Controls.play
  echo While Sound.playState ^<^> 1
  echo      WScript.Sleep 100
  echo Wend
)>sound22.vbs
start /min sound22.vbs
del *.vbs

It simply plays music\sia.mp3 in an infinite loop in the background.

Sometimes it fails to execute the sound22.vbs because it deletes it before the poor code could even execute it.

However, here are my main issues:

( echo Set Sound = CreateObject("WMPlayer.OCX.7"^)
  echo Sound.settings.volume = %volume2%
  echo While Sound.playState ^<^> 1
  echo      WScript.Sleep 100
  echo Wend
)>sound22.vbs
start /min sound22.vbs
del *.vbs

This code was supposed to, but doesn't, change the current volume to %volume2% without replaying the music.

  1. How can I do that?
  2. How can I control the WMPlayer object I created before?
  3. Even if I do, 2., will this second code be able to change the volume without replaying or pausing the music?
  4. Can I pause it using sound.controls.pause the same way and continue to play it again?
Compo
  • 30,301
  • 4
  • 20
  • 32
Visual917
  • 43
  • 10
  • Don't use START. Use cscript to execute the vbscript. – Squashman Jul 28 '18 at 20:27
  • 1
    Why are you using a batch file to create, run, and delete a VBScript? Just write the VBScript once and run that file. – Ansgar Wiechers Jul 28 '18 at 20:44
  • AnsgarWiechers it's a game. I have to use it in a bat script. Squashman thank you, but none of you has answered my question. – Visual917 Jul 29 '18 at 08:39
  • Have you implemented the advice @Squashman gave to you? Please [edit the code in your question](https://stackoverflow.com/posts/51574797/edit) to match so that we can advise you further. – Compo Jul 29 '18 at 10:32
  • @Visual917 Can you edit and post the whole batch game ? – Hackoo Jul 29 '18 at 13:15
  • @Hackoo Unfortunately not. I believe these are the only parts you need to answer my question. – Visual917 Jul 29 '18 at 13:28
  • @Visual917 In this case good luck for you ! – Hackoo Jul 29 '18 at 13:29
  • @Squashman that doesn't help at all. it shows the info of cscript, play the music but doesn't continue to execute the script in any way. – Visual917 Jul 29 '18 at 13:32
  • @Hackoo I'm sorry, I can't just copy the entire 500 line script here. How would that even help me? – Visual917 Jul 29 '18 at 13:35
  • @Visual917 You can't control the pause in your situation ! This why i asked for the whole code, but never mind ! you have always to restart the vbs again but it play from the beginning ! – Hackoo Jul 29 '18 at 13:39

2 Answers2

4

You can not control the previously created WMPlayer object by creating a new one, but you can control it by incorporating a mechanism which communicates with the created object.

Since batch scripts have no standard means for interprocess communication, the only option will be left, is to use an intermediate file as the communication medium.
Following is an standalone example code which demonstrate one way of doing it through batch script. It could be written differently but I've followed you design path for writing the code.

It plays the specified music/sound file and prompts the user to enter a command to send to the player to control it.

Implemented control command are: [0-100] for volume, mute, unmute, play, pause, replay, stop, open, quit

:: MusicPlayerAndController.bat
@echo off
setlocal DisableDelayedExpansion

set "PlayerMutex=BatchVbsSoundPlayer.mutex"
if "%~1"=="/LaunchAsyncPipedVbsPlayer" (
  %= Asynchronous Background Player =%
  %= Invoking only one instance of background player in the current directory =%

  9>&2 2>nul ( 8>"%PlayerMutex%" 2>&9 (
    call :LaunchAsyncPipedVbsPlayer
    (call,) %= Masks all other errors except than failure to hold PlayerMutex =%
  )) && del "%PlayerMutex%" >nul 2>&1 || echo WARNING: Another instance of player is already running.

  exit /b
)

%= Asynchronous Controller =%
cls
title Batch/VBS Music Player And Controller
set "PlayerCommandFile=VBSPlayerCommand.txt"
set "VBScriptPlayerApp=MediaPlayer.vbs"

:: Sample Music from Windows 7
set "SoundFile=%PUBLIC%\Music\Sample Music\Sleep Away.mp3"
if not exist "%SoundFile%" (
  set "SoundFile="
  echo Open a media file to start playing.
)

set "InitialVolume=30"
set "PingPipe=pingpipe"
(
  echo Dim Input : Dim Open
  echo Open = False
  echo Set Sound = CreateObject("WMPlayer.OCX.7"^)
  echo Sound.URL = "%SoundFile%"
  echo Sound.settings.volume = %InitialVolume%
  echo Sound.settings.setMode "loop", True
  echo Sound.Controls.play
  echo 'Give enough time for preparing new media, not relying on 'pingpipe' intervals
  echo WScript.Sleep 1000 
  echo Do Until WScript.StdIn.AtEndOfStream
  echo      Input = WScript.StdIn.ReadLine^(^)
  echo      If IsNumeric^(Input^) Then
  echo          Sound.settings.volume = Input
  echo      ElseIf Open = True Then
  echo          Open = False
  echo          Sound.Controls.stop
  echo          Sound.URL = Input
  echo          Sound.Controls.play
  echo          'Give enough time for preparing new media, not relying on 'pingpipe' intervals
  echo          WScript.Sleep 1000
  echo      Else
  echo          Select Case Trim^(LCase^(Input^)^)
  echo              Case "quit"
  echo                  Exit Do
  echo              Case "stop"
  echo                  Sound.Controls.stop
  echo              Case "pause"
  echo                  Sound.Controls.pause
  echo              Case "play"
  echo                  Sound.Controls.play
  echo              Case "replay"
  echo                  Sound.Controls.stop
  echo                  Sound.Controls.play
  echo              Case "mute"
  echo                  Sound.settings.mute = True
  echo              Case "unmute"
  echo                  Sound.settings.mute = False
  echo              Case "open"
  echo                  Open = True
  echo              Case "%PingPipe%"
  echo                  'Workaround for StdIn blokcing player from looping media
  echo                  WScript.Sleep 1
  echo          End Select
  echo      End If
  echo Loop
  echo Sound.Controls.stop
  echo Sound.close
)>"%VBScriptPlayerApp%"

:: Workaround for CMD %~0 bug
call :getBatFullPath @f0
:: Starting player
start "" /B "%COMSPEC%" /D /C "%@f0%" /LaunchAsyncPipedVbsPlayer
:: Give the player enough time to start
timeout /t 1 /nobreak >nul
del "%VBScriptPlayerApp%" >nul 2>&1


set "PlayerCommand=NONE"
set "QuitMsg=Player Closed."
:: Controller Command Loop
:PlayerCommandPrompt
set "LastCommand=%PlayerCommand%"
:PromptPreserveLastCommand
:: Making sure player is alive
del "%PlayerMutex%" >nul 2>&1
if not exist "%PlayerMutex%" (
  set "QuitMsg=Player Closed unexpectedly."
  goto :Quit
)
echo,
echo VbsPlayer Command Prompt
echo Valid Commands:
echo   [0-100] for volume, mute, unmute, play, pause, replay, stop, open, quit, cls (Clears Screen)
echo,
echo Last Command Sent: %LastCommand%
echo,
set "PlayerCommand="
set /p "PlayerCommand=Enter Command to send to VBS Player>"
if not defined PlayerCommand goto :PromptPreserveLastCommand
if /i "%PlayerCommand%"=="cls" cls & goto :PromptPreserveLastCommand
if /i "%PlayerCommand%"=="open" (
  setlocal EnableDelayedExpansion
  set "OK="
  set "NewMedia="
  set /p "NewMedia=Media File (Drag'n'Drop): "
  if defined NewMedia (
    set ^"NewMedia=!NewMedia:^"=!^"
    if exist "!NewMedia!" (
      (echo open&echo !NewMedia!)>"!PlayerCommandFile!"
      set "OK=1"
    )
  )
  if defined OK (
    endlocal
    goto :PlayerCommandPrompt
  ) else (
    endlocal
    goto :PromptPreserveLastCommand
  )
)
(echo %PlayerCommand%)>"%PlayerCommandFile%"
if /i "%PlayerCommand%"=="quit" goto :Quit
goto :PlayerCommandPrompt

:Quit
echo,
echo %QuitMsg%
pause
exit /b

:LaunchAsyncPipedVbsPlayer
del /f "%PlayerCommandFile%" >nul 2>&1
(
  (
    for /L %%# in (0,0,1) do @(
      type "%PlayerCommandFile%" && del "%PlayerCommandFile%" >&2
      timeout /t 1 /nobreak >&2
      %= This guarantees we will not loop infinitely when the player is closed =%
      %= Also used as a workaround for player 'loop music' to function correctly =%
      echo %PingPipe% 2>&1
    )
  )2>nul
)|cscript //nologo "%VBScriptPlayerApp%"
exit /b

:getBatFullPath
set "%~1=%~f0" & exit /b

It reads the file by batch code and sends the data though an established pipe to the VBS code.

The VBS code could simply read the file by itself without the need to use pipe, but then I had to embed a larger and more complex VBS code into the batch file with the echo commands which would be somewhat counterintuitive unless you decide to keep the VBS code separate from the batch code.

Or alternatively the VBS portion can be converted to JS which enables you to use true BAT/JS hybrid code without the need to write the JS part to a separate file each time the script is executed.

sst
  • 1,234
  • 1
  • 10
  • 13
  • Thank you so much, it helps. But does it loop? And greater question is, how do I make it not 'command prompt' I use it in my bat game. Also, I set the delay expansion enabled, but your code needs it to be disabled. How do I work around that? – Visual917 Aug 01 '18 at 18:59
  • I change the volume variable somewhere on the script, and I want to call the music function to change the volume. I want to play it in the beginning of the game in a different function. Also, can you tell me where do I need to put the other functions? Like, do I put :getBatFullPath in the very end? What I mean is, I don't want it to wait for an input. I just want to execute them all differently. Like 'goto :pause' 'goto :changevolume' (volume is already set to something) – Visual917 Aug 01 '18 at 19:06
  • Just study the code and try to understand how it works then adopt it to your needs. The purpose of the prompt is to provide a means to manually and quickly test the functionality of the code and see it in action. you don't need the prompt, just send the desired commands directly from your code. If you check the code carefully you will see that the commands are send this way `(echo %PlayerCommand%)>"%PlayerCommandFile%"`, so to pause the player `(echo pause)>"%PlayerCommandFile%"` , to set the volume to maximum `(echo 100)>"%PlayerCommandFile%"` ,etc. – sst Aug 02 '18 at 16:42
  • Before exiting the game, you should stop the player by sending the `stop` command. Keep the functions at the end of file and terminate your own code by `exit /b` to protect the functions. I didn't use *Delayed Expansion* because there was no need, if you need, just enable it. If you have any questions about particular aspects of batch scripting, like where to put a function or how to use them, how they work ,etc, then first try to search and if you couldn't find your answer then open up another question for each specific issue and solve the problems for your project step by step. – sst Aug 02 '18 at 17:19
  • I owe you so much man. Thank you for everything. I'm sorry for stealing your time. You rock! Thank you! – Visual917 Aug 02 '18 at 20:21
  • @Visual917, The player loop music issue fixed. Reading from `StdIn` blocks the player to start over playing the media. `open` command added for changing media so the `stop` command will not close the media player, `quit` command should be used instead. – sst Aug 05 '18 at 20:22
  • 1
    There is a simple technique to achieve a true batch/VBS hybrid. See the **UPDATE 2014-04-27** section at the bottom of [Is it possible to embed and execute VBScript within a batch file without using a temporary file?](https://stackoverflow.com/a/9074483/1012053) – dbenham Sep 19 '18 at 10:03
  • @sst I tried so much, but I can't quite achieve what I'm trying to do. I want to play music within a bat file. Like, 1- Play 2- Stop 3- Pause 4- Change Volume and all this will be in settings, music will loop and continue when the player's in game. how can i do this? :( idk where to put all the code – Visual917 Oct 30 '18 at 09:39
  • @sst, i don't want a standalone media player. i want to control them in my game's settings and i want to do something else while not being dependent to stay on the menu. also read what i said above. sorry – Visual917 Nov 08 '18 at 08:14
0

Give a try for this example in batch :

@echo off
Mode 60,5 & color 0A
Set "Volume=20"
Set "Title=Playing Music with volume of"
Title %Title% %Volume%%%
Set "URL=http://91.121.38.100:8010/;stream/1"
Set "VBS_Music=%Temp%\VBS_Music.vbs"
echo(
echo        Playing Radio Music with the volume of %Volume%%%
Call :PlayMusic "%URL%" %Volume%
Timeout /T 10 /nobreak>nul & cls & echo(
Set "Volume=100"
Title %Title% %Volume%%%
echo        Playing Radio Music with the volume of %Volume%%%
Call :StopMusic
Call :PlayMusic "%URL%" %Volume%
echo(
echo         Hit any key to stop the music and exit !
Pause>nul
Call :StopMusic
Exit
::*******************************************************************
:PlayMusic <URL> <Volume>
(
    echo Call Play("%~1",%2^)
    echo Sub Play(URL,Volume^)
    echo Set wmp = CreateObject("WMPlayer.OCX"^)
    echo wmp.settings.autoStart = True
    echo wmp.settings.volume = Volume
    echo wmp.URL = URL
    echo While wmp.Playstate ^<^> 1
    echo   WScript.Sleep 100 
    echo Wend
    echo End Sub
)>"%VBS_Music%"
Start "" "%VBS_Music%"
exit /b
::*******************************************************************
:StopMusic
Call :Add_backSlash "%VBS_Music%"
wmic Path win32_process Where "CommandLine Like '%%%Cmd_Path%%%'" Call Terminate>nul 2>&1
exit /b
::*******************************************************************
:Add_backSlash <String>
Rem Subroutine to replace the simple "\" by a double "\\" into a String
Set "MyPath=%1"
Set "String=\"
Set "NewString=\\"
Call Set "Cmd_Path=%%MyPath:%String%=%NewString%%%"
exit /b
::*******************************************************************
Hackoo
  • 15,943
  • 3
  • 28
  • 59
  • I'm sorry. This doesn't help. It plays the music but it can't change the volume when I use it again with a different volume value. Also, how am I even going to execute the pause and resume commands? – Visual917 Jul 29 '18 at 20:03
  • Okay, I did. I examined the code too. It changes the volume but restarts the music. Just like my code. I need it to "not restart" the music, but change the volume WHILE it is PLAYING. I tried your URL, and my local mp3 URL but it's the same. No help. – Visual917 Jul 30 '18 at 17:16