static BtPersistence * bt_wavelevel_persistence_load (const GType type, const BtPersistence * const persistence, xmlNodePtr node, GError ** err, va_list var_args) { BtWavelevel *const self = BT_WAVELEVEL (persistence); xmlChar *root_note_str, *rate_str, *loop_start_str, *loop_end_str; glong loop_start, loop_end; gulong rate; GstBtNote root_note; GST_DEBUG ("PERSISTENCE::wavelevel"); g_assert (node); // only deserialize customizable properties root_note_str = xmlGetProp (node, XML_CHAR_PTR ("root-note")); rate_str = xmlGetProp (node, XML_CHAR_PTR ("rate")); loop_start_str = xmlGetProp (node, XML_CHAR_PTR ("loop-start")); loop_end_str = xmlGetProp (node, XML_CHAR_PTR ("loop-end")); root_note = root_note_str ? atol ((char *) root_note_str) : GSTBT_NOTE_NONE; rate = rate_str ? atol ((char *) rate_str) : 0; loop_start = loop_start_str ? atol ((char *) loop_start_str) : 0; loop_end = loop_end_str ? atol ((char *) loop_end_str) : self->priv->length; g_object_set (self, "root-note", root_note, "rate", rate, "loop-start", loop_start, "loop-end", loop_end, NULL); xmlFree (root_note_str); xmlFree (rate_str); xmlFree (loop_start_str); xmlFree (loop_end_str); return BT_PERSISTENCE (persistence); }
/** * bt_wavelevel_new: * @song: the song the new instance belongs to * @wave: the wave the new wavelevel belongs to * @root_note: the keyboard note this sample is related * @length: the number of samples * @loop_start: the start of the loop * @loop_end: the end of the loop * @rate: the sampling rate * @sample: the sample data * * Create a new instance * * Returns: (transfer full): the new instance or %NULL in case of an error */ BtWavelevel * bt_wavelevel_new (const BtSong * const song, const BtWave * const wave, const GstBtNote root_note, const gulong length, const gulong loop_start, const gulong loop_end, const gulong rate, gconstpointer sample) { return BT_WAVELEVEL (g_object_new (BT_TYPE_WAVELEVEL, "song", song, "wave", wave, "root-note", root_note, "length", length, "loop_start", loop_start, "loop_end", loop_end, "rate", rate, "data", sample, NULL)); }
static void bt_wavelevel_finalize (GObject * const object) { const BtWavelevel *const self = BT_WAVELEVEL (object); GST_DEBUG ("!!!! self=%p", self); g_free (self->priv->sample); G_OBJECT_CLASS (bt_wavelevel_parent_class)->finalize (object); }
static void bt_wavelevel_constructed (GObject * object) { BtWavelevel *self = BT_WAVELEVEL (object); if (G_OBJECT_CLASS (bt_wavelevel_parent_class)->constructed) G_OBJECT_CLASS (bt_wavelevel_parent_class)->constructed (object); g_return_if_fail (BT_IS_SONG (self->priv->song)); g_return_if_fail (BT_IS_WAVE (self->priv->wave)); // add the wavelevel to the wave bt_wave_add_wavelevel (self->priv->wave, self); }
static void bt_wavelevel_dispose (GObject * const object) { const BtWavelevel *const self = BT_WAVELEVEL (object); return_if_disposed (); self->priv->dispose_has_run = TRUE; GST_DEBUG ("!!!! self=%p", self); g_object_try_weak_unref (self->priv->song); g_object_try_weak_unref (self->priv->wave); G_OBJECT_CLASS (bt_wavelevel_parent_class)->dispose (object); }
static xmlNodePtr bt_wavelevel_persistence_save (const BtPersistence * const persistence, xmlNodePtr const parent_node) { const BtWavelevel *const self = BT_WAVELEVEL (persistence); xmlNodePtr node = NULL; GST_DEBUG ("PERSISTENCE::wavelevel"); if ((node = xmlNewChild (parent_node, NULL, XML_CHAR_PTR ("wavelevel"), NULL))) { // only serialize customizable properties xmlNewProp (node, XML_CHAR_PTR ("root-note"), XML_CHAR_PTR (bt_str_format_uchar (self->priv->root_note))); xmlNewProp (node, XML_CHAR_PTR ("rate"), XML_CHAR_PTR (bt_str_format_ulong (self->priv->rate))); xmlNewProp (node, XML_CHAR_PTR ("loop-start"), XML_CHAR_PTR (bt_str_format_long (self->priv->loop_start))); xmlNewProp (node, XML_CHAR_PTR ("loop-end"), XML_CHAR_PTR (bt_str_format_long (self->priv->loop_end))); } return node; }
static void bt_wavelevel_get_property (GObject * const object, const guint property_id, GValue * const value, GParamSpec * const pspec) { const BtWavelevel *const self = BT_WAVELEVEL (object); return_if_disposed (); switch (property_id) { case WAVELEVEL_SONG: g_value_set_object (value, self->priv->song); break; case WAVELEVEL_WAVE: g_value_set_object (value, self->priv->wave); break; case WAVELEVEL_ROOT_NOTE: g_value_set_enum (value, self->priv->root_note); break; case WAVELEVEL_LENGTH: g_value_set_ulong (value, self->priv->length); break; case WAVELEVEL_LOOP_START: g_value_set_ulong (value, self->priv->loop_start); break; case WAVELEVEL_LOOP_END: g_value_set_ulong (value, self->priv->loop_end); break; case WAVELEVEL_RATE: g_value_set_ulong (value, self->priv->rate); break; case WAVELEVEL_DATA: g_value_set_pointer (value, self->priv->sample); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
/* bt_wave_save_to_fd: * * Write the sample data as a wav to a filedescriptor and keep it open */ static gboolean bt_wave_save_to_fd (const BtWave * const self) { gboolean res = TRUE; GstElement *pipeline = NULL; GstElement *src, *fmt, *enc, *sink; BtWavelevel *wavelevel; GstBus *bus = NULL; GstCaps *caps; //gchar *fn_wav; gulong srate, length, size, written; gint16 *data; gint fd = -1; if (!self->priv->wavelevels) { res = FALSE; GST_WARNING ("No wave data."); goto Error; } if ((fd = g_file_open_tmp (NULL, NULL, NULL)) == -1) { res = FALSE; GST_WARNING ("Can't create tempfile."); goto Error; } if ((self->priv->ext_fd = g_file_open_tmp (NULL, NULL, NULL)) == -1) { res = FALSE; GST_WARNING ("Can't create tempfile."); goto Error; } // the data is in the wave-level :/ wavelevel = BT_WAVELEVEL (self->priv->wavelevels->data); g_object_get (wavelevel, "data", &data, "length", &length, "rate", &srate, NULL); size = length * self->priv->channels * sizeof (gint16); GST_INFO ("about to format data as wav to fd=%d, %lu bytes to write", self->priv->ext_fd, size); // create saver pipeline pipeline = gst_pipeline_new ("wave-saver"); src = gst_element_factory_make ("fdsrc", NULL); fmt = gst_element_factory_make ("capsfilter", NULL); enc = gst_element_factory_make ("wavenc", NULL); sink = gst_element_factory_make ("fdsink", NULL); GST_DEBUG ("%p ! %p ! %p ! %p", src, fmt, enc, sink); // configure elements caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_AUDIO_NE (S16), "layout", G_TYPE_STRING, "interleaved", "rate", G_TYPE_INT, srate, "channels", G_TYPE_INT, self->priv->channels, NULL); g_object_set (fmt, "caps", caps, NULL); gst_caps_unref (caps); g_object_set (src, "fd", fd, "num-buffers", 1, "blocksize", size, NULL); g_object_set (sink, "fd", self->priv->ext_fd, "sync", FALSE, NULL); // add and link gst_bin_add_many (GST_BIN (pipeline), src, fmt, enc, sink, NULL); res = gst_element_link_many (src, fmt, enc, sink, NULL); if (!res) { GST_WARNING ("Can't link wave loader pipeline (src ! dec)."); goto Error; } bus = gst_element_get_bus (pipeline); GST_INFO ("run pipeline"); written = write (fd, data, size); size -= written; GST_INFO ("wrote %lu, todo %lu", written, size); lseek (fd, 0, SEEK_SET); // play and wait for EOS if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { GST_WARNING ("Can't set wave saver pipeline for to playing"); gst_element_set_state (pipeline, GST_STATE_NULL); res = FALSE; } else { GstMessage *msg; // we have num-buffers //gst_element_send_event(src,gst_event_new_eos()); // we need to run this sync'ed with eos GST_INFO ("saving sample ..."); msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, GST_CLOCK_TIME_NONE); if (msg) { switch (msg->type) { case GST_MESSAGE_EOS: res = TRUE; break; case GST_MESSAGE_ERROR: BT_GST_LOG_MESSAGE_ERROR (msg, NULL, NULL); res = FALSE; break; default: break; } gst_message_unref (msg); } } GST_INFO ("sample saved"); Error: if (bus) gst_object_unref (bus); if (pipeline) { gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); } if (fd != -1) close (fd); if (!res) wave_io_free (self); return res; }
static void bt_wavelevel_set_property (GObject * const object, const guint property_id, const GValue * const value, GParamSpec * const pspec) { const BtWavelevel *const self = BT_WAVELEVEL (object); return_if_disposed (); switch (property_id) { case WAVELEVEL_SONG: self->priv->song = BT_SONG (g_value_get_object (value)); g_object_try_weak_ref (self->priv->song); //GST_DEBUG("set the song for wavelevel: %p",self->priv->song); break; case WAVELEVEL_WAVE: self->priv->wave = BT_WAVE (g_value_get_object (value)); g_object_try_weak_ref (self->priv->wave); GST_DEBUG ("set the wave for wavelevel: %p", self->priv->wave); break; case WAVELEVEL_ROOT_NOTE: self->priv->root_note = g_value_get_enum (value); GST_DEBUG ("set the root-note for wavelevel: %d", self->priv->root_note); break; case WAVELEVEL_LENGTH: self->priv->length = g_value_get_ulong (value); GST_DEBUG ("set the length for wavelevel: %lu", self->priv->length); break; case WAVELEVEL_LOOP_START: self->priv->loop_start = g_value_get_ulong (value); GST_INFO ("loop: 0 / %lu .. %lu / %lu", self->priv->loop_start, self->priv->loop_end, self->priv->length); // make sure its less then loop_end/length if (self->priv->loop_end > 0) { if (self->priv->loop_start >= self->priv->loop_end) { GST_DEBUG ("clip loop-start by loop-end: %lu", self->priv->loop_end); self->priv->loop_start = self->priv->loop_end - 1; } } if (self->priv->length > 0) { if (self->priv->loop_start >= self->priv->length) { GST_DEBUG ("clip loop-start by length: %lu", self->priv->length); self->priv->loop_start = self->priv->length - 1; } } GST_DEBUG ("set the loop-start for wavelevel: %lu", self->priv->loop_start); break; case WAVELEVEL_LOOP_END: self->priv->loop_end = g_value_get_ulong (value); GST_INFO ("loop: 0 / %lu .. %lu / %lu", self->priv->loop_start, self->priv->loop_end, self->priv->length); // make sure its more then loop-start if (self->priv->loop_start > 0) { if (self->priv->loop_end < self->priv->loop_start) { GST_DEBUG ("clip loop-end by loop-start: %lu", self->priv->loop_start); self->priv->loop_end = self->priv->loop_start + 1; } } // make sure its less then or equal to length if (self->priv->length > 0) { if (self->priv->loop_end > self->priv->length) { GST_DEBUG ("clip loop-end by length: %lu", self->priv->length); self->priv->loop_end = self->priv->length; } } GST_DEBUG ("set the loop-start for wavelevel: %lu", self->priv->loop_start); break; case WAVELEVEL_RATE: self->priv->rate = g_value_get_ulong (value); GST_DEBUG ("set the rate for wavelevel: %lu", self->priv->rate); break; case WAVELEVEL_DATA: g_free (self->priv->sample); self->priv->sample = g_value_get_pointer (value); GST_DEBUG ("set the data-pointer for wavelevel: %p", self->priv->sample); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }