34from collections.abc
import Iterable
41gi.require_version(
'Gst',
'1.0')
42gi.require_version(
'GstAudio',
'1.0')
43from gi.repository
import GObject
44from gi.repository
import Gst
45from gi.repository
import GstAudio
51from ligo.segments
import segment
54__author__ =
"Kipp Cannon <kipp.cannon@ligo.org>, Chad Hanna <chad.hanna@ligo.org>, Drew Keppel <drew.keppel@ligo.org>"
68def repack_complex_array_to_real(arr):
70 Repack a complex-valued array into a real-valued array with twice
71 as many columns. Used to set complex arrays as values on elements
72 that expose them as real-valued array properties (gobject doesn't
73 understand complex numbers). The return value is a view into the
78 if arr.dtype.kind !=
"c":
80 assert arr.dtype.itemsize % 2 == 0
81 return arr.view(dtype = numpy.dtype(
"f%d" % (arr.dtype.itemsize // 2)))
84def repack_real_array_to_complex(arr):
86 Repack a real-valued array into a complex-valued array with half as
87 many columns. Used to retrieve complex arrays from elements that
88 expose them as real-valued array properties (gobject doesn't
89 understand complex numbers). The return value is a view into the
94 if arr.dtype.kind !=
"f":
96 return arr.view(dtype = numpy.dtype(
"c%d" % (arr.dtype.itemsize * 2)))
108def get_unit_size(caps):
110 name = struct.get_name()
111 if name ==
"audio/x-raw":
113 info = GstAudio.AudioInfo()
115 except NotImplementedError:
116 success, info = GstAudio.audio_info_from_caps(caps)
119 elif name ==
"video/x-raw" and struct[
"format"]
in (
"RGB",
"RGBA",
"ARGB",
"ABGR"):
120 return struct[
"width"] * struct[
"height"] * (3
if struct[
"format"] ==
"RGB" else 4)
121 raise ValueError(caps)
124def numpy_dtype_from_caps(caps):
126 GstAudio.AudioFormat.F32: numpy.dtype(
"float32"),
127 GstAudio.AudioFormat.F64: numpy.dtype(
"float64"),
128 GstAudio.AudioFormat.S8: numpy.dtype(
"int8"),
129 GstAudio.AudioFormat.U8: numpy.dtype(
"uint8"),
130 GstAudio.AudioFormat.S16: numpy.dtype(
"int16"),
131 GstAudio.AudioFormat.U16: numpy.dtype(
"uint16"),
132 GstAudio.AudioFormat.S32: numpy.dtype(
"int32"),
133 GstAudio.AudioFormat.U32: numpy.dtype(
"uint32")
136 custom_formats_dict = {
137 "Z64LE" : numpy.dtype(
"complex64"),
138 "Z128LE": numpy.dtype(
"complex128")
142 info = GstAudio.AudioInfo()
144 except NotImplementedError:
145 success, info = GstAudio.audio_info_from_caps(caps)
148 if info.finfo.format
in formats_dict:
149 return formats_dict[info.finfo.format]
150 elif caps.get_structure(0).get_string(
"format")
in custom_formats_dict:
151 return custom_formats_dict[caps.get_structure(0).get_string(
"format")]
153 raise ValueError(
"unknown GstAudioFormat : %s" % caps.get_structure(0).get_string(
"format"))
156def format_string_from_numpy_dtype(dtype, formats_dict = {
157 numpy.dtype(
"float32"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.F32),
158 numpy.dtype(
"float64"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.F64),
159 numpy.dtype(
"int8"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.S8),
160 numpy.dtype(
"uint8"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.U8),
161 numpy.dtype(
"int16"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.S16),
162 numpy.dtype(
"uint16"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.U16),
163 numpy.dtype(
"int32"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.S32),
164 numpy.dtype(
"uint32"): GstAudio.AudioFormat.to_string(GstAudio.AudioFormat.U32),
165 numpy.dtype(
"complex64") :
"Z64LE",
166 numpy.dtype(
"complex128") :
"Z128LE"
168 return formats_dict[dtype]
171def caps_from_array(arr, rate = None):
172 return Gst.Caps.from_string(
"audio/x-raw, format=(string)%s, rate=(int)%d, channels=(int)%d, layout=(string)interleaved, channel-mask=(bitmask)0" % (format_string_from_numpy_dtype(arr.dtype), rate, arr.shape[1]))
175def array_from_audio_sample(sample):
176 caps = sample.get_caps()
177 success, channels = caps.get_structure(0).get_int(
"channels")
180 buf = sample.get_buffer()
181 success, mapinfo = buf.map(Gst.MapFlags.READ)
184 a = numpy.frombuffer(mapinfo.data, dtype = numpy_dtype_from_caps(caps))
186 a.shape = len(a) // channels, channels
191def audio_buffer_from_array(arr, timestamp, offset, rate):
192 buf = Gst.Buffer.new_wrapped(arr.tobytes())
194 buf.duration = (Gst.SECOND * arr.shape[0] + rate // 2) // rate
196 buf.offset_end = offset + arr.shape[0]
209def parse_spectrum_message(message):
211 Parse a "spectrum" message from the lal_whiten element, return a
212 LAL REAL8FrequencySeries containing the strain spectral density.
214 s = message.get_structure()
215 psd = lal.CreateREAL8FrequencySeries(
216 name = s[
"instrument"]
if s.has_field(
"instrument")
else "",
217 epoch = lal.LIGOTimeGPS(0, message.timestamp),
219 deltaF = s[
"delta-f"],
220 sampleUnits = lal.Unit(s[
"sample-units"].strip()),
221 length = len(s[
"magnitude"])
223 psd.data.data = numpy.array(s[
"magnitude"])
236def parse_framesrc_tags(taglist):
238 instrument = taglist[
"instrument"]
242 channel_name = taglist[
"channel-name"]
245 if "units" in taglist:
246 sample_units = lal.Unit(taglist[
"units"].strip())
250 "instrument": instrument,
251 "channel-name": channel_name,
252 "sample-units": sample_units
258def format_property(prop):
260 Formats a property suitable for use in a GStreamer element.
261 Used to convert 2-dimensional data structures to an appropriate
262 type as needed, since the mechanics of how they are treated differ
263 between versions of pygobject. Acts as a no-op depending on the
264 property type and version of pygobject.
268 if GObject.pygobject_version < (3, 29, 0):
271 elif is_nested_listlike(prop):
272 if isinstance(prop, numpy.ndarray):
274 return [to_gvalue_array(row)
for row
in prop]
276 elif is_listlike(prop):
277 return to_gvalue_array(prop)
285def to_gvalue_array(arr):
287 Converts a list-like object to a GValueArray.
290 if isinstance(arr, segment):
291 st = Gst.Structure(f
"converter, array=(guint64) < {arr[0]:d}, {arr[1]:d} >")
292 elif isinstance(arr, numpy.ndarray):
294 st = Gst.Structure.new_empty(
"converter")
295 st[
"array"] = Gst.ValueArray(list(arr))
297 st = Gst.Structure.new_empty(
"converter")
298 st[
"array"] = Gst.ValueArray(list(arr))
299 result, val = st.get_array(
"array")
301 raise ValueError(
"could not convert input to GValueArray")
307def is_nested_listlike(obj):
309 Check if object is a nested list-like object.
311 if isinstance(obj, numpy.ndarray)
and obj.ndim > 2:
312 raise ValueError(
"Only 1D or 2D numpy arrays are supported")
313 elif isinstance(obj, numpy.ndarray)
and obj.ndim == 2:
315 elif is_listlike(obj):
316 return any(is_listlike(row)
for row
in obj)
325 Check if object is a list-like object.
327 if isinstance(obj, numpy.ndarray)
and obj.ndim == 1:
330 return isinstance(obj, Iterable)
and not isinstance(obj, str)