Skip to content

Instantly share code, notes, and snippets.

@ak-brodrigue
Last active June 6, 2023 13:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ak-brodrigue/b98d12e67167eb0e00291cd9c2c02164 to your computer and use it in GitHub Desktop.
Save ak-brodrigue/b98d12e67167eb0e00291cd9c2c02164 to your computer and use it in GitHub Desktop.
Creating Music objects with Wwise 2023.1+
# Copyright 2023 Audiokinetic Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from waapi import WaapiClient
from pathlib import Path
import json, tempfile, os, shutil
def Object(type, name, *children, **properties):
# Create the definition of a generic Wwise Object for ak.wwise.core.object.set
# For type list, refer to:
# https://www.audiokinetic.com/en/library/edge/?source=SDK&id=wobjects_index.html
# - children are taken as variable arguments
# - properties are taken as keyword arguments
# Basic definition
definition = {
"type" : type,
"name" : name
}
# Take any keyword argument, and convert it to a property
for key, value in properties.items():
definition['@'+key] = value
# Children can either be other definitions or file import instructions
if len(children) > 0 and isinstance(children[0], str):
# When we find a string as the first argument, we consider a file path
definition["import"] = {}
definition["import"]["files"] = []
for file in children:
definition["import"]["files"].append({
"audioFile" : file,
})
else:
# Else, we consider an array of children definitions
definition["children"] = children
return definition
def MusicSegment(name, *children, **properties):
# Create the definition for a Music Segment
return Object("MusicSegment", name, *children, **properties)
def MusicTrack(name, *children, **properties):
# Create the definition for a Music Track
return Object("MusicTrack", name, *children, **properties)
def MusicSwitchContainer(path, arguments, associations, *children, **properties):
# Create the definition for a Music Switch Container
path = Path(path)
name = path.stem
def build_path(idx_and_value):
index, value = idx_and_value
if value == '*':
return arguments[index]
return arguments[index] + '\\' + value
# Build the entries
entries = []
for key, value in associations.items():
tokens = enumerate(key.split('.'))
entry = Object("MultiSwitchEntry", '',
EntryPath = list(map( build_path, tokens)),
AudioNode = str(path.joinpath(value)))
entries.append(entry)
properties = properties or {}
properties['Arguments'] = arguments
properties['Entries'] = entries
return Object("MusicSwitchContainer", name, *children, **properties)
def MusicPlaylistContainer(name, *children, **properties):
# Create the definition for a Music Playlist Container
return Object("MusicPlaylistContainer", name, *children, **properties)
def MusicPlaylistItem(*children, **properties) :
# Create the definition for a Music Playlist Item
if 'Segment' in properties:
properties['PlaylistItemType'] = 1
return Object("MusicPlaylistItem", '', *children, **properties)
def MusicCue(name, *children, **properties):
# Create the definition for a Music Playlist Container
return Object("MusicCue", name, *children, **properties)
def MusicTransition(*children, **properties):
# Create the definition for a Music Transition
return Object("MusicTransition", '', *children, **properties)
def SwitchGroup(name, *children, **properties):
return Object("SwitchGroup", name, *children, **properties)
def Switch(name, *children, **properties):
return Object("Switch", name, *children, **properties)
# Connect (default URL)
client = WaapiClient()
# Generate some WAV files for demonstration
temp_dir = tempfile.TemporaryDirectory(prefix='WAV-import-')
frequencies = [100, 250, 300, 400, 700]
wav_args = list(map(lambda f: { "path" : os.path.join(str(temp_dir.name), "SFX_" + str(f) + ".wav"), "frequency": f, "waveform": "square" }, frequencies))
for arg in wav_args:
client.call("ak.wwise.debug.generateToneWAV", arg)
# Prepare the music hierarchy definition
root = R"\Interactive Music Hierarchy\Default Work Unit"
set_args = {
"objects": [
{
"object":R"\Switches\Default Work Unit",
"children":[
SwitchGroup("SWG_1",
Switch("SW_1_1"),
Switch("SW_1_2"),
),
SwitchGroup("SWG_2",
Switch("SW_2_1"),
Switch("SW_2_2"),
)
]
},
{
"object": root,
"children": [
MusicSwitchContainer(root + R"\MSC",
# The switches on which the music container is subscribed
[
R"\Switches\Default Work Unit\SWG_1",
R"\Switches\Default Work Unit\SWG_2"
],
# The association entries
{
R"SW_1_1.SW_2_1": R"MPL1",
R"SW_1_2.SW_2_1": R"MPL1",
R"*.SW_2_2": R"MPL2",
},
# The children
MusicPlaylistContainer(
R"MPL1",
MusicSegment("Segment1",
MusicTrack("TrackA", wav_args[0]["path"]), # Path to WAV file
MusicTrack("TrackB", wav_args[1]["path"]), # Path to WAV file
Cues = [
MusicCue('', CueType = 0, TimeMs=0),
MusicCue('', CueType = 1, TimeMs=1000)
]
),
MusicSegment("Segment2",
wav_args[2]["path"], # Path to WAV file
Cues = [
MusicCue('', CueType = 0, TimeMs=0), # Entry
MusicCue('', CueType = 1, TimeMs=1000), # Exit
MusicCue('Hello', CueType = 2, TimeMs=500) # Custom
]),
PlaylistRoot =
MusicPlaylistItem(
MusicPlaylistItem( Segment = root + "\MSC\MPL1\Segment1"),
MusicPlaylistItem( Segment = root + "\MSC\MPL1\Segment2"),
LoopCount = 0
)
),
MusicPlaylistContainer(
R"MPL2",
MusicSegment("Segment1",
wav_args[3]["path"], # Path to WAV file
Volume = -3),
MusicSegment("Segment2",
wav_args[4]["path"]), # Path to WAV file
PlaylistRoot =
MusicPlaylistItem(
MusicPlaylistItem( Segment = root + "\MSC\MPL2\Segment1"),
MusicPlaylistItem( Segment = root + "\MSC\MPL2\Segment2"),
LoopCount = 0
)
),
Volume = -12,
TransitionRoot = MusicTransition(
MusicTransition(), # default
MusicTransition(
SourceContextType = 2, # Object
SourceContextObject = root + R"\MSC\MPL1",
ExitSourceAt = 0, # Immediate
)
)
)
]
}
],
"onNameConflict": "merge",
"listMode":"replaceAll"
}
# Create the music hierarchy with the provided definition
result = client.call("ak.wwise.core.object.set", set_args)
print( json.dumps(result) )
# Disconnect
client.disconnect()
# clean up temp files
shutil.rmtree(temp_dir.name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment