bool buff_player_dacs_output(void *sample_buffer, size_t sample_length) { if (!buff_player_pcm_buf_fifo) return false; if (!sample_length) return (!buff_player_is_pcm_buf_fifo_full()); if (audio_mixer_dacs_output_direct(NULL, 0)) audio_mixer_dacs_output_direct(sample_buffer, sample_length); return buff_player_put_pcm_buf(sample_buffer, sample_length); }
//! //! @brief This callback function is called when the DAC interrupt has sent //! the buffer 'n-1' and switches to buffer 'n'. The aim of this function is thus to prepare //! the buffer 'n+1'; so that there is always a pending buffer for the interrupt. //! void dac_sample_sent_cb( void ) { uint16_t fifo_used_cnt=usb_stream_fifo_get_used_room(); if( fifo_used_cnt==0 ) { // Unexpected interrupt. usb_stream_context->synchronized = false; usb_stream_context->status = USB_STREAM_ERROR_NOT_SYNCHRONIZED; return; } // Previous buffer has been sent by the DAC driver. usb_stream_fifo_pull(); fifo_used_cnt--; if( fifo_used_cnt!=0 ) { void* buffer; uint16_t size; usb_stream_fifo_get(&buffer, &size); audio_mixer_dacs_output_direct(buffer, size/(usb_stream_context->channel_count*usb_stream_context->bits_per_sample/8)); } else { usb_stream_context->synchronized = false; usb_stream_context->status = USB_STREAM_ERROR_NOT_SYNCHRONIZED; } }
void buff_player_dacs_end_of_pcm_buf(void) { buff_player_pcm_buf_t pcm_buf; if (!buff_player_pcm_buf_fifo) return; buff_player_remove_used_pcm_buf(); if (!buff_player_peek_reload_pcm_buf(&pcm_buf)) return; audio_mixer_dacs_output_direct(pcm_buf.sample_buffer, pcm_buf.sample_length); }
static bool usb_stream_process(void) { buffer_t *input_buffer; #if (defined __GNUC__) dsp16_t * volatile dsp16_output_buffer; #else dsp16_t * dsp16_output_buffer; #endif int i, channel, size = 0; // If no buffer is ready, then set under flow marker if (usb_stream_context->current_full_buffer == -1) return false; // If the audio DAC is not ready to receive more data, then return if (!audio_mixer_dacs_output_direct(NULL, 0)) return false; // Select the current input buffer and make sure it is valid input_buffer = usb_stream_context->input_buffers[usb_stream_context->current_full_buffer]; // Make sure this buffer is not already in the process of resampling if (input_buffer->buffer_state != BUFFER_STATE_FULL) return false; // Mark this buffer as a "resampling" buffer input_buffer->buffer_state = BUFFER_STATE_RESAMPLING; // Select the current output buffer dsp16_output_buffer = (dsp16_t *) usb_stream_context->output_buffers[usb_stream_context->current_output_buffer]; for (channel=0; channel<usb_stream_context->nb_channels; channel++) { // Interpolates the current channel buffer dsp16_resampling_compute(usb_stream_context->ctx->resampling, usb_stream_context->output_temp_buffer, input_buffer->buffer[channel], channel); size = dsp16_resampling_get_output_current_buffer_size(usb_stream_context->ctx->resampling); // Fill the array with audio samples and mix the channels switch (usb_stream_context->nb_channels) { case 1: memcpy(dsp16_output_buffer, usb_stream_context->output_temp_buffer, usb_stream_context->input_buffer_size); break; case 2: for (i=0; i<size; i++) dsp16_output_buffer[i*2] = ((dsp16_t *) usb_stream_context->output_temp_buffer)[i]; break; default: for (i=0; i<size; i++) dsp16_output_buffer[i*usb_stream_context->nb_channels] = ((dsp16_t *) usb_stream_context->output_temp_buffer)[i]; } // change channel dsp16_output_buffer++; } // Re-selects the current output buffer dsp16_output_buffer = (dsp16_t *) usb_stream_context->output_buffers[usb_stream_context->current_output_buffer]; // Scale the output buffer if the scaling is set if (usb_stream_context->ctx->gain) dsp16_vect_realdiv(dsp16_output_buffer, dsp16_output_buffer, size * usb_stream_context->nb_channels, usb_stream_context->ctx->gain); // Send the buffer to the output channel audio_mixer_dacs_output_direct(dsp16_output_buffer, size); // Set the current input buffer as an empty buffer input_buffer->buffer_state = BUFFER_STATE_EMPTY; // Update the current output buffer index usb_stream_context->current_output_buffer = (usb_stream_context->current_output_buffer+1)%AUDIO_STREAM_NB_OUTPUT_BUFFERS; // Update the current full buffer pointer i = (usb_stream_context->current_full_buffer+1)%AUDIO_STREAM_NB_INPUT_BUFFERS; input_buffer = usb_stream_context->input_buffers[i]; if (input_buffer->buffer_state != BUFFER_STATE_FULL) i = -1; usb_stream_context->current_full_buffer = i; return true; }
//! //! @brief This function takes the stream coming from the selected USB pipe and sends //! it to the DAC driver. Moreover, it ensures that both input and output stream //! keep synchronized by adding or deleting samples. //! //! @param side USB_STREAM_HOST for USB host, USB_STREAM_DEVICE for device. //! @param pipe_in Number of the addressed pipe/endpoint //! @param pFifoCount (return parameter) NULL or pointer to the number of used buffers at this time //! //! @return status: (USB_STREAM_STATUS_OK, USB_STREAM_STATUS_NOT_SYNCHRONIZED, //! USB_STREAM_STATUS_SPEED_UP, USB_STREAM_STATUS_SLOW_DOWN, USB_STREAM_STATUS_BUFFER_OVERFLOW) //! int usb_stream_input(usb_stream_side_t side, uint8_t pipe_in, uint32_t* pFifoCount) { uint16_t fifo_used_cnt; uint16_t byte_count=0; uint32_t i; UnionPtr pswap; UnionPtr buffer; // We comes here since we have received something. Let's increase the internal // activity counter. usb_stream_cnt++; fifo_used_cnt=usb_stream_fifo_get_used_room(); if (pFifoCount) *pFifoCount = fifo_used_cnt; // usb_stream_fifo_get_free_room() if( USB_STREAM_BUFFER_NUMBER-fifo_used_cnt==0 ) { // Fatal error: even with the synchro mechanism acting, we are in a case in which the // buffers are full. usb_stream_context->synchronized = false; usb_stream_context->status = USB_STREAM_ERROR_NOT_SYNCHRONIZED; return usb_stream_context->status; } pswap.s8ptr = buffer.s8ptr = usb_stream_fifo_get_buffer(usb_stream_context->wr_id); #if USB_HOST_FEATURE == true if( side==USB_STREAM_HOST ) { byte_count=Host_byte_count(pipe_in); } #endif #if USB_DEVICE_FEATURE == true if( side==USB_STREAM_DEVICE ) { byte_count=Usb_byte_count(pipe_in); } #endif if( byte_count==0 ) { if( cpu_is_timeout(&broken_stream_timer) ) { usb_stream_context->status = USB_STREAM_ERROR_BROKEN_STREAM; } else { usb_stream_context->status = USB_STREAM_ERROR_NO_DATA; } return usb_stream_context->status; } else { // reset time out detection cpu_set_timeout(cpu_ms_2_cy(BROKEN_STREAM_TIMER, FCPU_HZ), &broken_stream_timer); } #if USB_HOST_FEATURE == true if( side==USB_STREAM_HOST ) { Host_reset_pipe_fifo_access(pipe_in); host_read_p_rxpacket(pipe_in, (void*)buffer.s8ptr, byte_count, NULL); } #endif #if USB_DEVICE_FEATURE == true if( side==USB_STREAM_DEVICE ) { Usb_reset_endpoint_fifo_access(pipe_in); usb_read_ep_rxpacket(pipe_in, (void*)buffer.s8ptr, byte_count, NULL); } #endif usb_stream_context->status = USB_STREAM_ERROR_NONE; if( byte_count > USB_STREAM_REAL_BUFFER_SIZE ) { byte_count = USB_STREAM_REAL_BUFFER_SIZE; usb_stream_context->status = USB_STREAM_ERROR_OVERFLOW; } // Swap samples since they are coming from the USB world. if( usb_stream_context->bits_per_sample==16 ) for( i=0 ; i<byte_count/(16/8) ; i++ ) pswap.s16ptr[i] = swap16(pswap.s16ptr[i]); else if( usb_stream_context->bits_per_sample==32 ) for( i=0 ; i<byte_count/(32/8) ; i++ ) pswap.s32ptr[i] = swap32(pswap.s32ptr[i]); //for( i=0 ; i<byte_count/2 ; i++ ) // printf("0x%04hx ", pswap[i]); //printf("\r\n"); usb_stream_fifo_push(byte_count); fifo_used_cnt++; if( !usb_stream_context->synchronized ) { usb_stream_context->status = USB_STREAM_ERROR_NOT_SYNCHRONIZED; if( fifo_used_cnt>=(USB_STREAM_BUFFER_NUMBER/2) ) { // We have enough buffers to start the playback. void* buffer; uint16_t size; // CS2200 cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); usb_stream_resync_step = PPM(usb_stream_resync_frequency, USB_STREAM_RESYNC_PPM_STEPS); usb_stream_resync_freq_ofst = usb_stream_resync_frequency; usb_stream_resync_ppm_ofst = 0; usb_stream_resync_last_room = fifo_used_cnt; #define TIMER_USB_RESYNC_CORRECTION 320 cpu_set_timeout( cpu_ms_2_cy(TIMER_USB_RESYNC_CORRECTION, FCPU_HZ), &usb_resync_timer ); usb_stream_context->synchronized=true; usb_stream_fifo_get(&buffer, &size); audio_mixer_dacs_output_direct(buffer, size/(usb_stream_context->channel_count*usb_stream_context->bits_per_sample/8)); // Fill also the reload stage of the PDCA. usb_stream_fifo_pull(); usb_stream_fifo_get(&buffer, &size); audio_mixer_dacs_output_direct(buffer, size/(usb_stream_context->channel_count*usb_stream_context->bits_per_sample/8)); } } return usb_stream_context->status; }