在 PortAudio 中输出
Output in PortAudio
我正在尝试学习 PortAudio,我正在学习 doc/src/tutorials 中的教程,这是 writing_a_callback.dox[ 中的代码=25=]:
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;
}
它工作正常,但我有几个问题:
- 我有一个带有 2 个
float
变量的 struct
,但是 PortAudio 如何知道哪个是左扬声器,哪个是右扬声器
- 在这个例子中,我传递给输出缓冲区的是什么、频率、音量或其他东西,以及我如何告诉 PortAudio 其他的信息,例如,如果我传递频率,那么我该如何告诉它调整音量
可能我遗漏了什么但是...我不知道
任何帮助的尝试表示赞赏
让我为您分解一下:
该结构定义了用于控制生成信号的“状态”。 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;
决定。
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 循环生成一种称为 sawtooth wave. The frequency is determined by the distance between the "teeth." If there are 1000 teeth per second of signal, a 1000 Hz tone is generated.The amplitude is determined by how tall the teeth are. If the peak-to-peak distance (bottom to top) is -1 to 1, that is an amplitude of 1 (100% for floating point samples). That is also 0 db, or unity gain. You can calculate db from the signal amplitude using equations defined in this article. (See Acoustics.) A good exercise would be to generate a different waveform, like a square wave, triangle wave, and sine wave 的周期函数。他们每个人都会产生具有独特特征的球场。
在代码中,左相位的幅度在每个样本中增加 0.01,在 200 个样本中从 -1 增加到 1。频率由该波形与音频流的采样率之间的关系确定。如果采样率为 48 kHz,则每个样本代表 1/48000 秒长的时间片。在这种情况下,信号频率为 240 Hz (48000 / 200
)
为了更好地理解这一切,您可以将此算法放入电子表格中并绘制点,或者甚至更好地放入 python 中并使用绘图库来可视化波浪。你也可以在纸上算出来。 x 值是时间,y 值是振幅。我还建议您继续阅读 pulse-code modulation (PCM)。 inputBuffer
和 outputBuffer
是 PCM 数据的缓冲区(数组)。它也是 WAV 文件中使用的编码。
我正在尝试学习 PortAudio,我正在学习 doc/src/tutorials 中的教程,这是 writing_a_callback.dox[ 中的代码=25=]:
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;
}
它工作正常,但我有几个问题:
- 我有一个带有 2 个
float
变量的struct
,但是 PortAudio 如何知道哪个是左扬声器,哪个是右扬声器 - 在这个例子中,我传递给输出缓冲区的是什么、频率、音量或其他东西,以及我如何告诉 PortAudio 其他的信息,例如,如果我传递频率,那么我该如何告诉它调整音量
可能我遗漏了什么但是...我不知道
任何帮助的尝试表示赞赏
让我为您分解一下:
该结构定义了用于控制生成信号的“状态”。 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;
决定。
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 循环生成一种称为 sawtooth wave. The frequency is determined by the distance between the "teeth." If there are 1000 teeth per second of signal, a 1000 Hz tone is generated.The amplitude is determined by how tall the teeth are. If the peak-to-peak distance (bottom to top) is -1 to 1, that is an amplitude of 1 (100% for floating point samples). That is also 0 db, or unity gain. You can calculate db from the signal amplitude using equations defined in this article. (See Acoustics.) A good exercise would be to generate a different waveform, like a square wave, triangle wave, and sine wave 的周期函数。他们每个人都会产生具有独特特征的球场。
在代码中,左相位的幅度在每个样本中增加 0.01,在 200 个样本中从 -1 增加到 1。频率由该波形与音频流的采样率之间的关系确定。如果采样率为 48 kHz,则每个样本代表 1/48000 秒长的时间片。在这种情况下,信号频率为 240 Hz (48000 / 200
)
为了更好地理解这一切,您可以将此算法放入电子表格中并绘制点,或者甚至更好地放入 python 中并使用绘图库来可视化波浪。你也可以在纸上算出来。 x 值是时间,y 值是振幅。我还建议您继续阅读 pulse-code modulation (PCM)。 inputBuffer
和 outputBuffer
是 PCM 数据的缓冲区(数组)。它也是 WAV 文件中使用的编码。