Having trouble with new UPBGE Audaspace syntax

Hi,

I’ve gone back to my project for UPBGE but I’m having trouble with Audaspace. I get an error about “buffer” needing two parameters which I started fixing. But then I get “File “getrotation.py”, line 38, in TypeError: The data needs to be supplied as float32 numpy array!”. I know what arrays are but need an example of using this type of array with Audaspace. Here is the code …

import bge
import aud
import bpy
import wave
import contextlib
import os, time
from bge import logic
from mathutils import Vector  
import numpy as np

backwards_position = None
forwards_position = None
trap = 0
timecode_path = "c:\Serato_Control_CD.wav"
device = aud.Device()
track = aud.Sound('timecode_path')
# Find length of track
with contextlib.closing(wave.open(timecode_path,'r')) as f:
    frames = f.getnframes()
    rate = f.getframerate()
    track_duration = frames / float(rate)
    print("Duration: ")
    print(track_duration)
# Setup handle to playing track.
# MUST be buffered for reverse. Where is this in documentation ?
track_buffered_reverse = track.buffer([0],44100)
track_buffered_forward = track.buffer()
track_reverse = track_buffered_reverse.reverse()
track_forward = track_buffered_forward

Any help appreciated !

There is no line 38. Only 29 lines. Did you forget to post some code?
I also do not get an error similar to yours, however I do get a missing argument error:

TypeError: Device() missing required argument 'type' (pos 1)

Thanks. I’ll repost the code soon.

When “track_buffered_reverse = track.buffer()” has no arguments error is …

Error: SetGlobalsAtTopofScript(Platter), Python script error
Traceback (most recent call last):
File “getrotation.py”, line 38, in
TypeError: buffer() takes exactly 2 arguments (0 given)
Duration:

When arguments are (track,44100) error is …

Error: SetGlobalsAtTopofScript(Platter), Python script error
Traceback (most recent call last):
File “getrotation.py”, line 38, in
TypeError: The data needs to be supplied as float32 numpy array!
Duration:

You can see my probably naïve attempt to create the array further up in the code when “track” is defined. I’m not familiar with these type of arrays and was having trouble finding relevant examples of how to use them. Also why does Audaspace use them now when my code was valid before ? A way of simply addressing multiple sound files ?

Full Blend download.

OK, I solved the problem. I just learnt how to address a 2 dimensional numpy array, so I guess that’s win :sunglasses:.

# DJ Turntable Physics Simulation, Michael Z Freeman, 2016

# See CHANGELOG.TXT, TODO.TXT & README.TXT in text data blog for changelog.

# Better name "Blender Game Engine DJ Turntable" ?

# This is the main Python file for the project. I decided not to pile everything into a single monolithic Python script without logic blocks. I found the logic blocks helped me think through the problems and keep things fairly simple. I also think the logic blocks make it easier for new comers to understand what is going on. So the script is arranged into "modules" that are referenced in the logic blocks. There is only one at the moment but that will probably change when, for example, file loading is added. Controls are only through the keyboard at the moment and will probably change:

#MOUSE CLICK LEFT/RIGHT: nudge/spin platter left/right.
# SPACE: start/stop.
# ALT: Deck on/off

import bge
import aud
import bpy
import wave
import contextlib
import os, time
from bge import logic
from mathutils import Vector  
import numpy as np

backwards_position = None
forwards_position = None
trap = 0
timecode_path = "c:\Serato_Control_CD.wav"
device = aud.Device()
timecode = aud.Sound.file('timecode_path')
track = np.array([['timecode_path']], dtype='float32')
# Find length of track
with contextlib.closing(wave.open(timecode_path,'r')) as f:
    frames = f.getnframes()
    rate = f.getframerate()
    track_duration = frames / float(rate)
    print("Duration: ")
    print(track_duration)
# Setup handle to playing track.
# MUST be buffered for reverse. Where is this in documentation ?
track_buffered_reverse = aud.Sound.buffer(track[0,0], 44100)
track_buffered_forward = track.buffer()
track_reverse = track_buffered_reverse.reverse()
track_forward = track_buffered_forward
#track_handle = device.play(track_reverse)
#track_handle.pitch = 1
# make sure its stopped because we have not moved the platter yet.
#track_handle.stop()

#def playTrack (cont):
#global track
#global track_handle
#global track_buffered
#global track_reverse
#global track_handle_forwards
#global track_handle_backwards
track_handle_forwards = device.play(track_forward)
track_handle_forwards.keep = True
track_handle_forwards.pause()
track_handle_forwards.loop_count = 0
track_handle_backwards = device.play(track_reverse)
track_handle_backwards.keep = True
track_handle_backwards.pause()
#reverse_handle.reverse
#track_handle.pitch = 1
#speed = setPitch
#print("Pitch: ")
#print(speed)
#track = track.pitch(speed) 
 
def setPitch (cont):
    global track
    global track_handle
    global track_buffered
    global track_reverse
    global track_forward
    global duration
    global trap
    
    #global backwards_position
    #global forwards_position
    #forwards_position = track_handle_forwards.position    
    #backwards_position = track_handle_backwards.position
    # Get object
    platter = bge.logic.getCurrentScene().objects['Platter']
    pitch_slider = bge.logic.getCurrentScene().objects['Pitch_control']
    pitch_adj = 8 * (pitch_slider.position.y + 1.3) / 100
    rot_speed = platter.worldAngularVelocity.z
    # - pitch_adj
    # "pitch_adj" figure has to be modified because we are returning "y" location of a non-centered model. 
    # "1.291654109954834" is "y" when the slider is in the middle.
    # Then adjust to standard Technics 1210 8% control of total pitch range.
    
    #print("Rotation speed: ")
    #print(rot_speed);
    speed = rot_speed * -1
    #print("Pitch: ")
    #print(speed)
    if speed >= 0:
        track_handle_backwards.pause()
        forwards_position = track_handle_forwards.position
        backwards_position = track_handle_backwards.position
        #backwards_position = track_handle_backwards.position
        #track_handle_forwards.position = forwards_position
        while (trap == 1):
            print("Forward trap triggered")
            track_handle_forwards.position = track_duration - backwards_position
            trap = 0     
        track_handle_forwards.resume()
        # playing/paused/stop status only ever shows as true ?
        #print("track_handle_backwards.status: ")
        #print(track_handle_backwards.status)
        #print(speed)
        #print("Pitch adj=")
        #print(pitch_adj)
        #print("Silder y=")
        #print(pitch_slider.position.y)
        # Set pitch of audio including pitch slider modifier.
        track_handle_forwards.pitch = speed
        #- pitch_adj + 1.291654109954834
        #print("track_handle_forwards.pitch: ")
        #print(track_handle_forwards.pitch)
        #print("track_handle_forwards.position: ")
        #print(track_handle_forwards.position)
    else:
        track_handle_forwards.pause()
        forwards_position = track_handle_forwards.position
        backwards_position = track_handle_backwards.position
        # Only set once until direction changes
        while (trap == 0):
            print("Backwards trap triggered")
            #print("Reverse Set: ")
            #print(backwards_position - track_duration + forwards_position)
            track_handle_backwards.position = track_duration - forwards_position
            trap = 1
        #forwards_position = track_handle_forwards.position
        #track_handle_backwards.position = backwards_position
        track_handle_backwards.resume()
        # Set pitch of audio including pitch slider modifier.
        track_handle_backwards.pitch = speed * -1
        #print("track_handle_backwards.pitch: ")
        #print(track_handle_backwards.pitch)
        #print("track_handle_backwards.position: ")
        #print(track_handle_backwards.position)   
    #track = track.pitch(speed)
    # rot_speed * -1
    #track = track.pitch(rot_speed)    
    # Old code for Actuator
    #sound.pitch = rot_speed * -1
    #print("Pitch: ")
    #print(track.pitch)
    #return rot_speed;
    
def checkBrake (cont):
    print("Brake was triggered.")
    
def applyForce (cont):
    if scratch == True:
        print("Mouse Left Click")
        cont = logic.getCurrentController()
        mouse = cont.sensors['Mouse.001']
        x,y = mouse.position
        platter = bge.logic.getCurrentScene().objects['Platter']
        platter.applyTorque((0, 0, x/50))
    
def applyForceRight (cont):
    print("Mouse Right Click")
    cont = logic.getCurrentController()
    mouse = cont.sensors['Mouse.003']
    x,y = mouse.position
    platter = bge.logic.getCurrentScene().objects['Platter']
    platter.applyTorque((0, 0, -x/50))

However I now get …

File “getrotation.py”, line 29, in
ValueError: could not convert string to float: ‘timecode_path’

So “buffer” no longer does what it used to do. Am I supposed to read in the data in some kind of raw form ? All I need to do is buffer the sound.

A lot seems to have changed with Audaspace with very little documentation or examples that I could find.

Should I be using the stable version of UPBGE which is an older version of Audaspace. Could some of Audaspace in the UPBGE alpha be buggy ?

You can find examples on it here:
https://docs.blender.org/api/current/aud.html
Note how the sound is passed into the buffer function.

I assume this is supposed to be the path to the wave, rather than a literal file called “timecode_path”? Remove the apostrophes to use the variable. Also, use double backslashes (e.g. “c:\\Serato_Control_CD.wav” because a single one is for escaping characters (e.g. “\n” for linebreak).

What are you trying to do with this line? I see you’re calling “buffer” on it later on, but that implies you’re expecting it to be an AUD sound.

I’d recommend starting with a script that successfully plays sound based on the example in my link at the top. Then, add each extra bit one at a time and test things in between so you know which bits aren’t working.

Cheers. I used the example in your link for a test. I stripped out everything from the “getrotation” script and replaced with the test …

import aud

device = aud.Device()
# load sound file (it can be a video file with audio)
sound = aud.Sound('c:\\Serato_Control_CD.wav')

# play the audio, this return a handle to control play/pause
handle = device.play(sound)
# if the audio is not too big and will be used often you can buffer it
sound_buffered = aud.Sound.buffer(sound)
handle_buffered = device.play(sound_buffered)

# stop the sounds (otherwise they play until their ends)
handle.stop()
handle_buffered.stop()

When I load this blend file the sound immediately starts playing … the first “handle = device.play(sound)”, however it never gets buffered and gives the same error (this is everything reported in the console window …

Read prefs: C:\Users\tempo\AppData\Roaming\UPBGE\Blender\3.0\config\userpref.blend
Icon can not be set, using original Buttons.
Icon can not be set, using original Buttons.
register_class(...):
Warning: 'NODE_MT_category_Vector Math' doesn't have an alpha-numeric suffix
register_class(...):
Warning: 'NODE_MT_category_Armature / Rig' doesn't have an alpha-numeric suffix
register_class(...):
Warning: 'NODE_MT_category_Ray Casts' doesn't have an alpha-numeric suffix
Read blend: C:\Users\tempo\Documents\UPBGE Development\UPBGE Alpha\Aud Test Example PLAYS THE SOUND NO ARRAY NONSENSE MESSAGE.blend
Traceback (most recent call last):
  File "C:\Users\tempo\Documents\UPBGE Development\UPBGE Alpha\Aud Test Example PLAYS THE SOUND NO ARRAY NONSENSE *MESSAGE.blend\getrotation.py", line 10, in <module>*
*TypeError: buffer() takes exactly 2 arguments (1 given)*

Unless this is some kind of bug it seems to be a new way of calling the buffer in a new update of Audaspace (or it was added by UPBGE devs) as defined here. I still don’t understand why it requires an array if that’s what’s going on. If I want to use multiple sounds then I’d use an array, but I only have a SINGLE sound. What happened to keep it simple, eh ?

EDIT: Got it ! I hope !

This DOES work …

import aud

device = aud.Device()
# load sound file (it can be a video file with audio)
sound = aud.Sound('c:\\Serato_Control_CD.wav')

# play the audio, this return a handle to control play/pause
#handle = device.play(sound)
# if the audio is not too big and will be used often you can buffer it
sound_buffered = aud.Sound.cache(sound)
handle_buffered = device.play(sound_buffered)

# stop the sounds (otherwise they play until their ends)
#handle.stop()
#handle_buffered.stop()

In their wisdom Audaspace or the UPBGE devs have changed what used to be “buffer” into “cache”. This is what had been confusing me all along. “buffer” now “Creates a sound from a data buffer” (the opposite of what buffer used to do, confused yet? Even worse the example is wrong at the top of the docs page.). The array it requires is created from “data” … “Retrieves the data of the sound as numpy array.”.

“cache” … “Caches a sound into RAM” which is what older version of Aud “buffer” used to do.

1 Like

Oof. Glad that you sorted it out!

Thanks for sharing your working code. That’ll be useful for others that run across the same issue.

I had a look at one of my old projects and found I’d done it an entirely different way (no idea if this would still work):

import aud
device = aud.Device()

sound = aud.Factory.file('mysound.ogg')
bufferedSound = sound.buffer()
handle = device.play(bufferedSound)
1 Like

It won’t because “buffer” has been changed to “cache”. I need to change all my “buffered” variable names to “cached”.

Eample at top of upbge.org/api/aud.html is incorrect · Issue #1545 · UPBGE/upbge (github.com)