def get(self, key): """ Get a data member with a conversion to Python type as much as possible. Params: - key is the id of the data member to get. Returns the value with a Python type. """ value = getattr(self._c_struct, key) # Ease manipulation of char* data members, convert to python str() if self._types[key] == ffi.typeof("char *") and value != ffi.NULL: return ffi.string(value).decode("utf-8") # Ease manipulation of force_vector_s fields elif self._types[key] == ffi.typeof("struct force_vector_s"): return { "tempo": (value.tempo), "amplitude": value.amplitude, "frequency": value.frequency, "attack": value.attack } # Same for array of int fields elif self._types[key] == ffi.typeof("int8_t *"): return [value[i] for i in range(self.get("nSamples"))] # Else, returning the value directly should be safe else: return value
def set(self, key, value): """ Set a data member with a conversion from Python type as much as possible. Params: - key is the id of the data member to set. - value is the value to set. """ # Ease manipulation of char* data members, convert python str() if self._types[key] == ffi.typeof("char *") and value != ffi.NULL: if value != ffi.NULL: value = ffi.new("char[]", value.encode("utf-8")) # Keep the value in a dict in this object to keep it alive and safe # from the garbage collector. self._keepalive[key] = value # Same for force_vector_s fields elif self._types[key] == ffi.typeof("struct force_vector_s"): if value == ffi.NULL: return # Initialization from a valid initializer (tuple, list or dict) value = ffi.new("struct force_vector_s[]", [value]) self._keepalive[key] = value value = value[0] # Same for array of int fields elif self._types[key] == ffi.typeof("int8_t *"): if value != ffi.NULL: value = ffi.new("int8_t[]", value) # Keep the value in a dict in this object to keep it alive and safe # from the garbage collector. self._keepalive[key] = value else: # Nothing to do pass return setattr(self._c_struct, key, value)
def __init__(self, filename=None, initializer=None, c_struct=None): """ Initialize a new `bl_song` object. Params: - filename is a path to a file to load and analyze (optional). - initializer is an initializer to feed to `ffi.new` allocation call. Valid initializers are a list or tuple or dict of the field values. - c_struct is a preexisting `struct bl_song *` to use for initialization. """ # Initializing private data members if c_struct is not None: self._c_struct = c_struct else: self._c_struct = ffi.new("struct bl_song *", initializer) self._types = {i[0]: i[1].type for i in ffi.typeof("struct bl_song").fields} # _keepalive is useful to prevent garbage # collector from collecting dynamically allocated # data members self._keepalive = {} if filename is not None: self.analyze(filename)
def __init__(self, filename=None, initializer=None, c_struct=None): """ Initialize a new `bl_song` object. Params: - filename is a path to a file to load and analyze (optional). - initializer is an initializer to feed to `ffi.new` allocation call. Valid initializers are a list or tuple or dict of the field values. - c_struct is a preexisting `struct bl_song *` to use for initialization. """ # Initializing private data members if c_struct is not None: self._c_struct = c_struct else: self._c_struct = ffi.new("struct bl_song *", initializer) self._types = { i[0]: i[1].type for i in ffi.typeof("struct bl_song").fields } # _keepalive is useful to prevent garbage # collector from collecting dynamically allocated # data members self._keepalive = {} if filename is not None: self.analyze(filename)