pico-extras/src/common/pico_audio/include/pico/audio.h

309 wiersze
9.1 KiB
C

/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_AUDIO_H
#define _PICO_AUDIO_H
#include "pico.h"
#include "pico/util/buffer.h"
#include "hardware/sync.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file audio.h
* \defgroup pico_audio pico_audio
*
* Common API for audio output
*
*/
// PICO_CONFIG: SPINLOCK_ID_AUDIO_FREE_LIST_LOCK, Spinlock number for the audio free list, min=0, max=31, default=6, group=audio
#ifndef SPINLOCK_ID_AUDIO_FREE_LIST_LOCK
#define SPINLOCK_ID_AUDIO_FREE_LIST_LOCK 6
#endif
// PICO_CONFIG: SPINLOCK_ID_AUDIO_PREPARED_LISTS_LOCK, Spinlock number for the audio prepared list, min=0, max=31, default=7, group=audio
#ifndef SPINLOCK_ID_AUDIO_PREPARED_LISTS_LOCK
#define SPINLOCK_ID_AUDIO_PREPARED_LISTS_LOCK 7
#endif
// PICO_CONFIG: PICO_AUDIO_NOOP, Enable/disable audio by forcing NOOPS, type=bool, default=0, group=audio
#ifndef PICO_AUDIO_NOOP
#define PICO_AUDIO_NOOP 0
#endif
#define AUDIO_BUFFER_FORMAT_PCM_S16 1 ///< signed 16bit PCM
#define AUDIO_BUFFER_FORMAT_PCM_S8 2 ///< signed 8bit PCM
#define AUDIO_BUFFER_FORMAT_PCM_U16 3 ///< unsigned 16bit PCM
#define AUDIO_BUFFER_FORMAT_PCM_U8 4 ///< unsigned 16bit PCM
/** \brief Audio format definition
*/
typedef struct audio_format {
uint32_t sample_freq; ///< Sample frequency in Hz
uint16_t format; ///< Audio format \ref audio_formats
uint16_t channel_count; ///< Number of channels
} audio_format_t;
/** \brief Audio buffer format definition
*/
typedef struct audio_buffer_format {
const audio_format_t *format; ///< Audio format
uint16_t sample_stride; ///< Sample stride
} audio_buffer_format_t;
/** \brief Audio buffer definition
*/
typedef struct audio_buffer {
mem_buffer_t *buffer;
const audio_buffer_format_t *format;
uint32_t sample_count;
uint32_t max_sample_count;
uint32_t user_data; // only valid while the user has the buffer
// private - todo make an internal version
struct audio_buffer *next;
} audio_buffer_t;
typedef struct audio_connection audio_connection_t;
typedef struct audio_buffer_pool {
enum {
ac_producer, ac_consumer
} type;
const audio_format_t *format;
// private
audio_connection_t *connection;
spin_lock_t *free_list_spin_lock;
// ----- begin protected by free_list_spin_lock -----
audio_buffer_t *free_list;
spin_lock_t *prepared_list_spin_lock;
audio_buffer_t *prepared_list;
audio_buffer_t *prepared_list_tail;
} audio_buffer_pool_t;
typedef struct audio_connection audio_connection_t;
struct audio_connection {
audio_buffer_t *(*producer_pool_take)(audio_connection_t *connection, bool block);
void (*producer_pool_give)(audio_connection_t *connection, audio_buffer_t *buffer);
audio_buffer_t *(*consumer_pool_take)(audio_connection_t *connection, bool block);
void (*consumer_pool_give)(audio_connection_t *connection, audio_buffer_t *buffer);
audio_buffer_pool_t *producer_pool;
audio_buffer_pool_t *consumer_pool;
};
/*! \brief Allocate and initialise an audio producer pool
* \ingroup pico_audio
*
* \param format Format of the audio buffer
* \param buffer_count \todo
* \param buffer_sample_count \todo
* \return Pointer to an audio_buffer_pool
*/
audio_buffer_pool_t *audio_new_producer_pool(audio_buffer_format_t *format, int buffer_count,
int buffer_sample_count);
/*! \brief Allocate and initialise an audio consumer pool
* \ingroup pico_audio
*
* \param format Format of the audio buffer
* \param buffer_count
* \param buffer_sample_count
* \return Pointer to an audio_buffer_pool
*/
audio_buffer_pool_t *audio_new_consumer_pool(audio_buffer_format_t *format, int buffer_count,
int buffer_sample_count);
/*! \brief Allocate and initialise an audio wrapping buffer
* \ingroup pico_audio
*
* \param format Format of the audio buffer
* \param buffer \todo
* \return Pointer to an audio_buffer
*/
audio_buffer_t *audio_new_wrapping_buffer(audio_buffer_format_t *format, mem_buffer_t *buffer);
/*! \brief Allocate and initialise an new audio buffer
* \ingroup pico_audio
*
* \param format Format of the audio buffer
* \param buffer_sample_count \todo
* \return Pointer to an audio_buffer
*/
audio_buffer_t *audio_new_buffer(audio_buffer_format_t *format, int buffer_sample_count);
/*! \brief Initialise an audio buffer
* \ingroup pico_audio
*
* \param audio_buffer Pointer to an audio_buffer
* \param format Format of the audio buffer
* \param buffer_sample_count \todo
*/
void audio_init_buffer(audio_buffer_t *audio_buffer, audio_buffer_format_t *format, int buffer_sample_count);
/*! \brief \todo
* \ingroup pico_audio
*
* \param ac \todo
* \param buffer \todo
* \return Pointer to an audio_buffer
*/
void give_audio_buffer(audio_buffer_pool_t *ac, audio_buffer_t *buffer);
/*! \brief \todo
* \ingroup pico_audio
*
* \return Pointer to an audio_buffer
*/
audio_buffer_t *take_audio_buffer(audio_buffer_pool_t *ac, bool block);
/*! \brief \todo
* \ingroup pico_audio
*
*/
static inline void release_audio_buffer(audio_buffer_pool_t *ac, audio_buffer_t *buffer) {
buffer->sample_count = 0;
give_audio_buffer(ac, buffer);
}
/*! \brief \todo
* \ingroup pico_audio
*
* todo we are currently limited to 4095+1 input samples
* step is fraction of an input sample per output sample * 0x1000 and should be < 0x1000 i.e. we we are up-sampling (otherwise results are undefined)
*/
void audio_upsample(int16_t *input, int16_t *output, uint output_count, uint32_t step);
/*! \brief \todo
* \ingroup pico_audio
* similar but the output buffer is word aligned, and we output an even number of samples.. this is slightly faster than the above
* todo we are currently limited to 4095+1 input samples
* step is fraction of an input sample per output sample * 0x1000 and should be < 0x1000 i.e. we we are up-sampling (otherwise results are undefined)
*/
void audio_upsample_words(int16_t *input, int16_t *output_aligned, uint output_word_count, uint32_t step);
/*! \brief \todo
* \ingroup pico_audio
*/
void audio_upsample_double(int16_t *input, int16_t *output, uint output_count, uint32_t step);
/*! \brief \todo
* \ingroup pico_audio
*/
void audio_complete_connection(audio_connection_t *connection, audio_buffer_pool_t *producer,
audio_buffer_pool_t *consumer);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *get_free_audio_buffer(audio_buffer_pool_t *context, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
void queue_free_audio_buffer(audio_buffer_pool_t *context, audio_buffer_t *ab);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *get_full_audio_buffer(audio_buffer_pool_t *context, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
void queue_full_audio_buffer(audio_buffer_pool_t *context, audio_buffer_t *ab);
/*! \brief \todo
* \ingroup pico_audio
*
* generally an pico_audio connection uses 3 of the defaults and does the hard work in one of them
*/
void consumer_pool_give_buffer_default(audio_connection_t *connection, audio_buffer_t *buffer);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *consumer_pool_take_buffer_default(audio_connection_t *connection, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
void producer_pool_give_buffer_default(audio_connection_t *connection, audio_buffer_t *buffer);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *producer_pool_take_buffer_default(audio_connection_t *connection, bool block);
enum audio_correction_mode {
none,
fixed_dither,
dither,
noise_shaped_dither,
};
struct buffer_copying_on_consumer_take_connection {
struct audio_connection core;
audio_buffer_t *current_producer_buffer;
uint32_t current_producer_buffer_pos;
};
struct producer_pool_blocking_give_connection {
audio_connection_t core;
audio_buffer_t *current_consumer_buffer;
uint32_t current_consumer_buffer_pos;
};
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *mono_to_mono_consumer_take(audio_connection_t *connection, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *mono_s8_to_mono_consumer_take(audio_connection_t *connection, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *stereo_to_stereo_consumer_take(audio_connection_t *connection, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *mono_to_stereo_consumer_take(audio_connection_t *connection, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
audio_buffer_t *mono_s8_to_stereo_consumer_take(audio_connection_t *connection, bool block);
/*! \brief \todo
* \ingroup pico_audio
*/
void stereo_to_stereo_producer_give(audio_connection_t *connection, audio_buffer_t *buffer);
// not worth a separate header for now
typedef struct __packed pio_audio_channel_config {
uint8_t base_pin;
uint8_t dma_channel;
uint8_t pio_sm;
} pio_audio_channel_config_t;
#ifdef __cplusplus
}
#endif
#endif //_AUDIO_H