ChangeSpeed Not Working in Scripting in Python

Hi all,

I’m using pyaudacity to batch edit some files in Audacity using the mod-script-pipes functionality. My commands in general work fine, with the exception of the command where I use ChangeSpeed:

import pyaudacity as pa
import time

filename = "/absolute/path/to/file/test.mp3"
savefilename = "/absolute/path/to/file/test_short.mp3"

# New window
pa.do('New')

# Import the file clip
pa.do(f"Import2: Filename=\"{filename}\"")

# Select the clip
pa.do('SelectAll')

# Change the tempo
pa.do("ChangeSpeed: Percentage=\"-10.0\"")

# Change the pitch
#pa.do(f"ChangePitch: Percentage=\"-10.0\"")

# Export
pa.do(f"Export2: Filename=\"{savefilename}\"")

pa.do('Close')

The frustrating thing is that if I run the ChangePitch command instead (which is commented out there, but has the same arguments), the entire script works fine (resulting in a -10% change in pitch in the saved mp3 file). I think maybe the name of ChangeSpeed effect has been changed without an update in the documentation, but I’m honestly not sure. Here’s the error output for the ChangeSpeed line:

---------------------------------------------------------------------------
PyAudacityException                       Traceback (most recent call last)
Cell In[14], line 19
    16 pa.do('SelectAll')
    18 # Change the tempo
---> 19 pa.do("ChangeSpeed: Percentage=\"-10.0\"")
    21 # Change the pitch back up
    22 #pa.do(f"ChangePitch: Percentage=\"-10.0\"")
    23 print("e")

File ~/miniconda3/envs/ncg/lib/python3.13/site-packages/pyaudacity/__init__.py:137, in do(command)
   135 # sys.stdout.write(response + '\n')  # DEBUG
   136 if 'BatchCommand finished: Failed!' in response:
--> 137     raise PyAudacityException(response)
   139 return response

PyAudacityException: Your batch command of ChangeSpeed was not recognized.
BatchCommand finished: Failed!

I’m using Audacity 3.7.3, on macOS Sonoma 14.7, and Python 3.13.2. I’m assuming this is an issue with something on Audacity’s end, rather than PyAudacity, since I also tried these commands using the do_command function defined in pipe_test.py, and I get the same pattern where ChangeSpeed doesn’t work, but ChangePitch is fine. I can also use Change Speed and Pitch just fine through the GUI.

Thank you for your help!

That library is the problem. I love the developer’s books, but the code in that module is fragile, has not been updated since March 2023, and is now broken.

I thought so too, but I also can’t run ChangeSpeed it using the code from Audacity (adapted from pipe_test.py, which is from Audacity’s github):

import os
import sys


if sys.platform == 'win32':
    print("pipe-test.py, running on windows")
    TONAME = '\\\\.\\pipe\\ToSrvPipe'
    FROMNAME = '\\\\.\\pipe\\FromSrvPipe'
    EOL = '\r\n\0'
else:
    print("pipe-test.py, running on linux or mac")
    TONAME = '/tmp/audacity_script_pipe.to.' + str(os.getuid())
    FROMNAME = '/tmp/audacity_script_pipe.from.' + str(os.getuid())
    EOL = '\n'

print("Write to  \"" + TONAME +"\"")
if not os.path.exists(TONAME):
    print(" ..does not exist.  Ensure Audacity is running with mod-script-pipe.")
    sys.exit()

print("Read from \"" + FROMNAME +"\"")
if not os.path.exists(FROMNAME):
    print(" ..does not exist.  Ensure Audacity is running with mod-script-pipe.")
    sys.exit()

print("-- Both pipes exist.  Good.")

TOFILE = open(TONAME, 'w')
print("-- File to write to has been opened")
FROMFILE = open(FROMNAME, 'rt')
print("-- File to read from has now been opened too\r\n")


def send_command(command):
    """Send a single command."""
    print("Send: >>> \n"+command)
    TOFILE.write(command + EOL)
    TOFILE.flush()

def get_response():
    """Return the command response."""
    result = ''
    line = ''
    while True:
        result += line
        line = FROMFILE.readline()
        if line == '\n' and len(result) > 0:
            break
    return result

def do_command(command):
    """Send one command, and return the response."""
    send_command(command)
    response = get_response()
    print("Rcvd: <<< \n" + response)
    return response

filename = "/path/to/test.mp3"
savefilename = "/path/to/test_short.mp3"

do_command('New')
do_command(f"Import2: Filename=\"{filename}\"")
do_command('SelectAll')
do_command("ChangeSpeed: Percentage=\"-10.0\"")  # This throws the error
#do_command('SelectAll')
#do_command("ChangePitch: Percentage=\"10.0\"") # This doesn't when uncommented
do_command(f"Export2: Filename=\"{savefilename}\"")

The output of the above is as follows, you can see the command doesn’t work using the script from Audacity’s github:

pipe-test.py, running on linux or mac
Write to  "/tmp/audacity_script_pipe.to.501"
Read from "/tmp/audacity_script_pipe.from.501"
-- Both pipes exist.  Good.
-- File to write to has been opened
-- File to read from has now been opened too

Send: >>> 
New
Rcvd: <<< 

BatchCommand finished: OK

Send: >>> 
Import2: Filename="/path/to/test.mp3"
Rcvd: <<< 

BatchCommand finished: OK

Send: >>> 
SelectAll
Rcvd: <<< 

BatchCommand finished: OK

Send: >>> 
ChangeSpeed: Percentage="-10.0"
Rcvd: <<< 
Your batch command of ChangeSpeed was not recognized.
BatchCommand finished: Failed!

Send: >>> 
Export2: Filename="/path/to/test_short.mp3"
Rcvd: <<< 
Exported to MP3 format: /path/to/test_short.mp3
BatchCommand finished: OK

So the issue is seemingly with ChangeSpeed, not the module.

The name of the command has changed from ChangeSpeed to ChangeSpeedAndPitch, but they didn’t think to update the documentation.