我正在努力学习PortAudio,我正在学习doc/src/教程中的教程,这是writing_a_callback.dox中的代码
typedef struct
{
float left_phase;
float right_phase;
}
paTestData;
/* This routine will be called by the PortAudio engine when audio is needed.
** It may called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int patestCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
/* Cast data passed through stream to our structure. */
paTestData *data = (paTestData*)userData;
float *out = (float*)outputBuffer;
unsigned int i;
(void) inputBuffer; /* Prevent unused variable warning. */
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = data->left_phase; /* left */
*out++ = data->right_phase; /* right */
/* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
data->left_phase += 0.01f;
/* When signal reaches top, drop back down. */
if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
/* higher pitch so we can distinguish left and right. */
data->right_phase += 0.03f;
if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
}
return 0;
}它很好,但我有几个问题:
struct变量的float,但是PortAudio如何知道哪个是左边的,哪个是右边的也许我错过了什么但是..。我不知道
任何帮助的尝试都会受到赞赏。
发布于 2021-01-29 02:39:29
我来帮你解释一下:
此结构定义用于控制生成信号的“状态”。left_phase用于存储左侧通道的下一个示例值。right_phase存储右通道的下一个值。
typedef struct
{
float left_phase;
float right_phase;
}
paTestData;这是在PortAudio中注册的回调函数。PortAudio将数据从输入流(麦克风)传递到inputBuffer以供用户处理。用户将数据传递给发送到声卡输出流(扬声器)的outputBuffer。userData是在注册回调时传递的一些值或结构。在本例中,它是paTestData的一个实例。
/* This routine will be called by the PortAudio engine when audio is needed.
** It may called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int patestCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
/* Cast data passed through stream to our structure. */
paTestData *data = (paTestData*)userData;
float *out = (float*)outputBuffer;
unsigned int i;
(void) inputBuffer; /* Prevent unused variable warning. */这个for循环是产生信号的地方,每次一个帧。framesPerBuffer (部分由用户在注册回调时确定,部分由OS确定)控制生成了多少样例。循环的每一次迭代生成两个音频数据样本。对于立体声流,样品是交错的。第一个示例进入左侧通道。第二个样本进入正确的通道。
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = data->left_phase; /* left */
*out++ = data->right_phase; /* right */
/* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
data->left_phase += 0.01f;
/* When signal reaches top, drop back down. */
if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
/* higher pitch so we can distinguish left and right. */
data->right_phase += 0.03f;
if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
}
return 0;
}此代码由for循环控制频率和幅度(体积)。每个样本表示该时间段的信号的幅度(由采样率决定)。在这种情况下,频率由值0.01f和0.03f决定。幅值由if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;确定,左通道由if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;确定,右侧通道由if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;确定。
data->left_phase += 0.01f;
/* When signal reaches top, drop back down. */
if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
/* higher pitch so we can distinguish left and right. */
data->right_phase += 0.03f;
if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;正如代码注释中所描述的那样,for循环生成一种称为锯齿波的周期函数。频率取决于“牙齿”之间的距离。如果信号每秒有1000个齿,一个1000赫兹的音调是generated.The的振幅是由牙齿有多高决定的。如果峰到峰的距离(从下到上)为-1到1,即为1的振幅(浮点样本为100%)。这也是0 db,或单位增益。您可以使用定义的在本文中方程从信号幅度计算db。(见声学。)一个很好的练习是生成一个不同的波形,如方波、三角波和正弦波。它们每个都会产生具有独特特性的音高。
在代码中,左相位每个样本的幅值为0.01,从-1增加到1/ 200。频率由该波形与音频流的采样率之间的关系决定。如果采样率为48 kHz,那么每个样本代表1/48000秒长的一段时间。在这种情况下,信号频率为240 Hz (48000 / 200)。
为了更好地理解这一点,您可以将此算法放入电子表格并绘制点,或者更好地将其绘制到python中,并使用绘图库来可视化波形。你也可以把它写在纸上。X值是时间,y值是振幅.我还建议你读一读脉冲码调制(PCM)。inputBuffer和outputBuffer是PCM数据的缓冲区(数组)。它也是WAV文件中使用的编码。
https://stackoverflow.com/questions/65806332
复制相似问题