1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
"""Audio function module.
Contains the definition of the Audio, the audio primitive.
"""
import xml.etree.ElementTree as et
from .function import Function
from ..constants import AUDIO, BXW
from ..exceptions import LoadError
class Audio(Function):
"""Class representing an audio cue.
This is the primitive for audio, and all sound cues must be based in some manner off of
Audio. This function merely plays a single audio file once, starting at t=0.
The duration of the audio is automatically determined and is zero if the file does not
exist or is unsupported by ffmpeg.
"""
scope = ()
audio_scope = frozenset()
actual_duration = 0
def __init__(self, w, id_ = None, name = None, fade_in = 0, fade_out = 0,
filename: str = None):
super().__init__(w=w, type_=AUDIO, id_=id_, name=name, duration=0,
fade_in=fade_in, fade_out=fade_out)
self._filename = filename
if filename is not None:
self.duration = self.w.get_audio_length(filename)
self.audio_scope = frozenset(((filename,),))
else:
self.duration = 0
self.audio_scope = frozenset()
self.actual_duration = self.duration
def get_data(self):
return None
def copy_data(self, data):
return None
def render(self, t, data = None):
return ((),
((self.id, self._filename, 0, self.fade_in, self.duration, self.fade_out),),
None)
@property
def filename(self):
"""Return the current audio filename."""
return self._filename
@filename.setter
def filename(self, value: str):
"""Set the current audio filename, updating the duration."""
if value is not None:
self.duration = self.w.get_audio_length(value)
self.audio_scope = frozenset(((value,),))
else:
self.duration = 0
self.audio_scope = frozenset()
self._filename = value
self.w.function_changed(self)
def serialize(self) -> et.Element:
e = et.Element(BXW+"function")
e.set("type", self.type)
e.set("id", str(self.id))
e.set("name", self.name)
e.set("fade-in", str(self.fade_in))
e.set("fade-out", str(self.fade_out))
if self.filename is not None:
filename = et.SubElement(e, BXW+"filename")
filename.text = self.filename
return e
@classmethod
def deserialize(cls, w, e):
if e.tag != BXW+"function":
raise LoadError("Invalid function tag")
elif e.get("type") != AUDIO:
raise LoadError("Load delegated to wrong class (this is a bug)")
id_ = cls.int_or_none(e.get("id"))
if id_ is None:
raise LoadError("Function tag has invalid/missing ID")
name = e.get("name")
fade_in = e.get("fade-in")
try:
fade_in = int(fade_in) if fade_in else 0
except ValueError:
raise LoadError("Invalid fade in")
fade_out = e.get("fade-out")
try:
fade_out = int(fade_out) if fade_out else 0
except ValueError:
raise LoadError("Invalid fade out")
if len(e) > 1:
raise LoadError("Audio tag can have at most one filename")
elif len(e) == 1:
filename, = e
filename = filename.text
else:
filename = None
return cls(w=w, id_=id_, name=name, filename=filename, fade_in=fade_in,
fade_out=fade_out)
|