f.rodrigues
f.rodrigues

Reputation: 3587

Python Change Master/Application Volume

How do I change it?

I'm looking for something like:

SetMasterVolume(0.5)
SetAppVolume('FooBar',0.5)

I tried using ctypes.windll.winmm, but I can't find much documentation on how to use it.

Thanks in advance.

Upvotes: 20

Views: 63887

Answers (12)

mathematics-and-caffeine
mathematics-and-caffeine

Reputation: 2169

One liner using helper function

If not installed, run: pip install pynput

"""
You must set n to the volume levels your computer has.
x: volume in percent, 0 min, 1 max
"""
def set_volume(x):
    n = 100 # volume levels your computer has

    keyboard = Controller()
    pause = 0.0001
    desired_level = int(x*n)
    
    # go to 0 first since we dont know the current volume level
    press_count = int(n/2)
    for _ in range(press_count):
        keyboard.press(Key.media_volume_down)
        keyboard.release(Key.media_volume_down)
        time.sleep(pause)

    press_count = int(desired_level/2)
    for _ in range(press_count):
        keyboard.press(Key.media_volume_up)
        keyboard.release(Key.media_volume_up)
        time.sleep(pause)

Example: set_volume(0.5)

Upvotes: 0

Robert
Robert

Reputation: 11

I figured out a way to set the master volume using numpy, while still using Pycaw.

from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
import numpy as np

Get the audio output device

devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))

Set the desired volume in percentage (0 to 100)

desired_vol = 50

Get the volume range (min and max values in dB)

vol_range = volume.GetVolumeRange()
min_vol = vol_range[0]
max_vol = vol_range[1]

Convert the desired volume percentage to volume level in dB

desired_vol_db = np.interp(desired_vol, [0, 100], [min_vol, max_vol])
volume.SetMasterVolumeLevelScalar(desired_vol / 100, None)

Print the current volume percentage

curr_vol = int(volume.GetMasterVolumeLevelScalar() * 100)
print(f'Volume set to: {int(curr_vol)} %')

Upvotes: 0

Ethan
Ethan

Reputation: 9

you can set the number of presses in pyautogui and create to an even output

e.g. 43 input = 42 output

imports used:

import pyautogui as p
import math, time
from tkinter import simpledialog

using tkinter askdialog to get an input

volume = simpledialog.askinteger("new volume", "what would you like the volume to be?")

and setting the volume

def set_vol(new_volume):
    p.press('volumedown', presses = 50) #sets volume to zero
    time.sleep(0.5) #using time.sleep to space the presses 
    x = math.floor(new_volume / 2) #setting the amount of presses required
    p.press('volumeup', presses = x) #setting volume

running the definition

set_vol(volume) 

Upvotes: 0

Daiton
Daiton

Reputation: 9

import pyautogui

x = 50
a = (x//2)
pyautogui.press('volumeup',a)

#this code will increase computer master volume by even numbers

Upvotes: 0

gabeyww
gabeyww

Reputation: 39

You can use pyautogui:

import pyautogui
pyautogui.FAILSAFE = False
x = 1

while x < 10:
    pyautogui.press('volumedown')
    x+=1

Upvotes: 0

Augurkenplukker12
Augurkenplukker12

Reputation: 155

from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
 
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(
   IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
volume = cast(interface, POINTER(IAudioEndpointVolume))
 
# Control volume
#volume.SetMasterVolumeLevel(-0.0, None) #max
#volume.SetMasterVolumeLevel(-5.0, None) #72%
volume.SetMasterVolumeLevel(-10.0, None) #51%

Upvotes: 2

dragon445
dragon445

Reputation: 119

this is a very roundabout way to do it but it works.you can simulate the key presses for the computers master volume with pynput. it works but it is quite inacurate.

from pynput.keyboard import Key,Controller
keyboard = Controller()
import time
while True:
    for i in range(10):
        keyboard.press(Key.media_volume_up)
        keyboard.release(Key.media_volume_up)
        time.sleep(0.1)
    for i in range(10):
        keyboard.press(Key.media_volume_down)
        keyboard.release(Key.media_volume_down)
        time.sleep(0.1)
    time.sleep(2) 

this is an ok method of doing it. every keypress and release is equal to about 2 volume . hope this is somewhat helpful!

Upvotes: 9

Matthew Moisen
Matthew Moisen

Reputation: 18279

I ripped this from here and modified it to use functions only.

import time
import ctypes

# Import the SendInput object
SendInput = ctypes.windll.user32.SendInput

# C struct redefinitions
PUL = ctypes.POINTER(ctypes.c_ulong)

class KeyBoardInput(ctypes.Structure):
    _fields_ = [
        ("wVk", ctypes.c_ushort),
        ("wScan", ctypes.c_ushort),
        ("dwFlags", ctypes.c_ulong),
        ("time", ctypes.c_ulong),
        ("dwExtraInfo", PUL)
    ]

class HardwareInput(ctypes.Structure):
    _fields_ = [
        ("uMsg", ctypes.c_ulong),
        ("wParamL", ctypes.c_short),
        ("wParamH", ctypes.c_ushort)
    ]

class MouseInput(ctypes.Structure):
    _fields_ = [
        ("dx", ctypes.c_long),
        ("dy", ctypes.c_long),
        ("mouseData", ctypes.c_ulong),
        ("dwFlags", ctypes.c_ulong),
        ("time",ctypes.c_ulong),
        ("dwExtraInfo", PUL)
    ]

class Input_I(ctypes.Union):
    _fields_ = [
        ("ki", KeyBoardInput),
        ("mi", MouseInput),
        ("hi", HardwareInput)
    ]

class Input(ctypes.Structure):
    _fields_ = [
        ("type", ctypes.c_ulong),
        ("ii", Input_I)
    ]

VK_VOLUME_MUTE = 0xAD
VK_VOLUME_DOWN = 0xAE
VK_VOLUME_UP = 0xAF

def key_down(keyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBoardInput(keyCode, 0x48, 0, 0, ctypes.pointer(extra))
    x = Input( ctypes.c_ulong(1), ii_ )
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))


def key_up(keyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBoardInput(keyCode, 0x48, 0x0002, 0, ctypes.pointer(extra))
    x = Input(ctypes.c_ulong(1), ii_)
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))


def key(key_code, length = 0):    
    key_down(key_code)
    time.sleep(length)
    key_up(key_code)


def volume_up():
    key(VK_VOLUME_UP)


def volume_down():
    key(VK_VOLUME_DOWN)

def set_volume(int):
    for _ in range(0, 50):
        volume_down()
    for _ in range(int / 2):
        volume_up()

Upvotes: 3

Medoalmasry
Medoalmasry

Reputation: 546

I know this is too late but if someone is still looking for a seamless solution

Download this exe application from here

and just call this command using python

./SoundVolumeView.exe /SetVolume "High Definition Audio Device\Device\Speakers" 50 

Upvotes: 3

jblz
jblz

Reputation: 1029

I'd hope after 5 years this is no longer a problem for you, but I've just had to do the same thing. It's possible using the PyCaw library.

Simple proof of concept, based on PyCaw's examples

from __future__ import print_function
from pycaw.pycaw import AudioUtilities, ISimpleAudioVolume


def main():
    sessions = AudioUtilities.GetAllSessions()
    for session in sessions:
        volume = session._ctl.QueryInterface(ISimpleAudioVolume)
        if session.Process and session.Process.name() == "vlc.exe":
            print("volume.GetMasterVolume(): %s" % volume.GetMasterVolume())
            volume.SetMasterVolume(0.6, None)


if __name__ == "__main__":
    main()

Upvotes: 46

KodyVanRy
KodyVanRy

Reputation: 1108

So instead of editing my old answer I'm adding a new post to allow others who use self to use my old code and anyone who's not, to use my new code.

def get_master_volume():
    proc = subprocess.Popen('/usr/bin/amixer sget Master', shell=True, stdout=subprocess.PIPE)
    amixer_stdout = proc.communicate()[0].split('\n')[4]
    proc.wait()

    find_start = amixer_stdout.find('[') + 1
    find_end = amixer_stdout.find('%]', find_start)

    return float(amixer_stdout[find_start:find_end])

def set_master_volume(volume):
    val = float(int(volume))

    proc = subprocess.Popen('/usr/bin/amixer sset Master ' + str(val) + '%', shell=True, stdout=subprocess.PIPE)
    proc.wait()

Upvotes: 0

KodyVanRy
KodyVanRy

Reputation: 1108

First import subprocess import subprocess

Then to get the master volume

def get_master_volume(self):
    proc = subprocess.Popen('/usr/bin/amixer sget Master', shell=True, stdout=subprocess.PIPE)
    amixer_stdout = proc.communicate()[0].split('\n')[4]
    proc.wait()

    find_start = amixer_stdout.find('[') + 1
    find_end = amixer_stdout.find('%]', find_start)

    return float(amixer_stdout[find_start:find_end])

And to set the Master volume

def set_master_volume(self, widget):
    val = self.volume
    val = float(int(val))
    proc = subprocess.Popen('/usr/bin/amixer sset Master ' + str(val) + '%', shell=True, stdout=subprocess.PIPE)
    proc.wait()

Upvotes: -1

Related Questions