static void * play_loop(void *arg) { nsf_t * nsf = app.nsf; pdebug("nsf : play-thread\n"); if (!app.nsf) { going = FALSE; } pdebug("nsf : going [%s]\n", going ? "Yes" : "No"); app.cur_track = 0; nsf->cur_frame = nsf->cur_frame_end = 0; while (going) { if (nsf->cur_frame >= nsf->cur_frame_end) { int next_track = app.cur_track+1; pdebug("nsf : frame elapsed [%u > %u] -> track #%02d\n", nsf->cur_frame,nsf->cur_frame_end, next_track); if (next_track > app.n_tracks) { pdebug("nsf : reach last song\n"); going = FALSE; break; } SetChangeTrack(next_track, -1); } if (ApplyChangeTrack() < 0) { going = FALSE; break; } if (!app.bufcnt) { /* Run a frame. */ nsf_frame(nsf); apu_process(app.buffer, app.buflen); app.bufptr = app.buffer; app.bufcnt = app.buflen; } if (going) { int tosend = app.bufcnt << 1; while (nosefart_ip.output->buffer_free() < tosend && going) { xmms_usleep(30000); } nosefart_ip.add_vis_pcm(nosefart_ip.output->written_time(), FMT_S16_LE, 1, tosend, app.bufptr); nosefart_ip.output->write_audio(app.bufptr, tosend); tosend >>= 1; app.bufcnt -= tosend; app.bufptr += tosend; } } pdebug("nsf : decoder loop end\n"); SetChangeTrack(0, -1); ApplyChangeTrack(); if (app.nsf) { nsf_free(&app.nsf); app.nsf = nsf = 0; } /* Make sure the output plugin stops prebuffering */ if (nosefart_ip.output) { pdebug("nsf : free audio buffer.\n"); nosefart_ip.output->buffer_free(); } going = FALSE; pdebug("nsf : decode finish\n"); play_thread = 0; pthread_exit(NULL); }
static void nsf_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { nsf_decoder_t *this = (nsf_decoder_t *) this_gen; audio_buffer_t *audio_buffer; if (buf->decoder_flags & BUF_FLAG_HEADER) { /* When the engine sends a BUF_FLAG_HEADER flag, it is time to initialize * the decoder. The buffer element type has 4 decoder_info fields, * 0..3. Field 1 is the sample rate. Field 2 is the bits/sample. Field * 3 is the number of channels. */ this->sample_rate = buf->decoder_info[1]; this->bits_per_sample = buf->decoder_info[2]; this->channels = buf->decoder_info[3]; /* take this opportunity to initialize stream/meta information */ this->stream->meta_info[XINE_META_INFO_AUDIOCODEC] = strdup("NES Music (Nosefart)"); this->song_number = buf->content[4]; /* allocate a buffer for the file */ this->nsf_size = BE_32(&buf->content[0]); this->nsf_file = xine_xmalloc(this->nsf_size); this->nsf_index = 0; /* peform any other required initialization */ this->last_pts = -1; this->iteration = 0; return; } /* accumulate chunks from the NSF file until whole file is received */ if (this->nsf_index < this->nsf_size) { xine_fast_memcpy(&this->nsf_file[this->nsf_index], buf->content, buf->size); this->nsf_index += buf->size; if (this->nsf_index == this->nsf_size) { /* file has been received, proceed to initialize engine */ nsf_init(); this->nsf = nsf_load(NULL, this->nsf_file, this->nsf_size); if (!this->nsf) { printf ("nsf: could not initialize NSF\n"); /* make the decoder return on every subsequent buffer */ this->nsf_index = 0; } this->nsf->current_song = this->song_number; nsf_playtrack(this->nsf, this->nsf->current_song, this->sample_rate, this->bits_per_sample, this->channels); } return; } /* if the audio output is not open yet, open the audio output */ if (!this->output_open) { this->output_open = this->stream->audio_out->open( this->stream->audio_out, this->stream, this->bits_per_sample, this->sample_rate, (this->channels == 2) ? AO_CAP_MODE_STEREO : AO_CAP_MODE_MONO); } /* if the audio still isn't open, do not go any further with the decode */ if (!this->output_open) return; /* check if a song change was requested */ if (buf->decoder_info[1]) { this->nsf->current_song = buf->decoder_info[1]; nsf_playtrack(this->nsf, this->nsf->current_song, this->sample_rate, this->bits_per_sample, this->channels); } /* time to decode a frame */ if (this->last_pts != -1) { /* process a frame */ nsf_frame(this->nsf); /* get an audio buffer */ audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); if (audio_buffer->mem_size == 0) { printf ("nsf: Help! Allocated audio buffer with nothing in it!\n"); return; } apu_process(audio_buffer->mem, this->sample_rate / this->nsf->playback_rate); audio_buffer->vpts = buf->pts; audio_buffer->num_frames = this->sample_rate / this->nsf->playback_rate; this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); } this->last_pts = buf->pts; }
static void play_loop (GstPad * pad) { GstFlowReturn ret; GstNsfDec *nsfdec; GstBuffer *out; gint64 value, offset, time; GstFormat format; nsfdec = GST_NSFDEC (gst_pad_get_parent (pad)); out = gst_buffer_new_and_alloc (nsfdec->blocksize); gst_buffer_set_caps (out, GST_PAD_CAPS (pad)); nsf_frame (nsfdec->nsf); apu_process (GST_BUFFER_DATA (out), nsfdec->blocksize / nsfdec->bps); /* get offset in samples */ format = GST_FORMAT_DEFAULT; gst_nsfdec_src_convert (nsfdec->srcpad, GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &offset); GST_BUFFER_OFFSET (out) = offset; /* get current timestamp */ format = GST_FORMAT_TIME; gst_nsfdec_src_convert (nsfdec->srcpad, GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &time); GST_BUFFER_TIMESTAMP (out) = time; /* update position and get new timestamp to calculate duration */ nsfdec->total_bytes += nsfdec->blocksize; /* get offset in samples */ format = GST_FORMAT_DEFAULT; gst_nsfdec_src_convert (nsfdec->srcpad, GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &value); GST_BUFFER_OFFSET_END (out) = value; format = GST_FORMAT_TIME; gst_nsfdec_src_convert (nsfdec->srcpad, GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &value); GST_BUFFER_DURATION (out) = value - time; if ((ret = gst_pad_push (nsfdec->srcpad, out)) != GST_FLOW_OK) goto pause; done: gst_object_unref (nsfdec); return; /* ERRORS */ pause: { const gchar *reason = gst_flow_get_name (ret); GST_DEBUG_OBJECT (nsfdec, "pausing task, reason %s", reason); gst_pad_pause_task (pad); if (ret == GST_FLOW_UNEXPECTED) { /* perform EOS logic, FIXME, segment seek? */ gst_pad_push_event (pad, gst_event_new_eos ()); } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) { /* for fatal errors we post an error message */ GST_ELEMENT_ERROR (nsfdec, STREAM, FAILED, (NULL), ("streaming task paused, reason %s", reason)); gst_pad_push_event (pad, gst_event_new_eos ()); } goto done; } }