控制某个 MP 对象在播放音频文件时更改音量设置

To control a certain MP object to alter volume settings while playing an audio file

我的 .bat 脚本中有这段代码。

( 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

它只是在后台无限循环播放 music\sia.mp3

有时它无法执行 sound22.vbs 因为它在糟糕的代码甚至可以执行它之前就删除了它。

但是,我的主要问题是:

( 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

此代码本应将当前音量更改为 %volume2%,但并未重播音乐。

  1. 我该怎么做?
  2. 如何控制我之前创建的 WMPlayer 对象?
  3. 即使我这样做,2.,第二个代码是否能够在不重播或暂停音乐的情况下改变音量?
  4. 我可以用同样的方法 sound.controls.pause 暂停并再次继续播放吗?

批量尝试此示例:

@echo off
Mode 60,5 & color 0A
Set "Volume=20"
Set "Title=Playing Music with volume of"
Title %Title% %Volume%%%
Set "URL=https://stream.initialradio.fr:8443/djbuzz-192k.mp3"
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
::*******************************************************************

您无法通过创建一个新对象来控制先前创建的 WMPlayer 对象,但您可以通过合并一种与创建的对象通信的机制来控制它。

由于批处理脚本没有进程间通信的标准方式,唯一的选择就是使用中间文件作为通信媒介。
以下是一个独立的示例代码,演示了通过批处理脚本执行此操作的一种方法。 它可以以不同的方式编写,但我遵循了您编写代码的设计路径。

它播放指定的music/sound文件并提示用户输入命令发送给播放器来控制它。

执行的控制命令有:[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

它通过批处理代码读取文件并通过已建立的管道将数据发送到 VBS 代码。

VBS 代码可以简单地自行读取文件而无需使用管道,但后来我不得不将更大更复杂的 VBS 代码嵌入到批处理文件中 echo 命令,除非您决定将 VBS 代码与批处理代码分开。

或者 VBS 部分可以转换为 JS,这使您能够使用真正的 BAT/JS 混合代码,而无需将 JS 部分写入每次执行脚本时单独的文件。