Я играю с pa_simple
API, чтобы лучше понять цифровой звук.Я написал некоторый код для подачи сгенерированных пользователем аудиоданных на сервер pulseaudio:
char buff[2];
while (playing) {
timePassed += periodMicros;
int val = userFunc(timePassed/1000000.0);
buff[0] = (val >> 0) & 0xff;
buff[1] = (val >> 1) & 0xff;
int error;
pa_simple_write(s, buff, 2, &error);
}
func
генерирует простую синусоидальную волну, подобную этой:
uint16_t func(double time)
{
double op = sin(2*3.14*freq * time);
return op * 100;
}
Создает заметкукак и ожидалось, но потребляет до 50% процессора на моей машине из-за неограниченного цикла while
в первом кодовом блоке.Поэтому я попытался исправить это так:
void _mainLoop() {
char buff[2*bufSize];
while (playing) {
for ( int i = 0; i < bufSize; i++ ) {
uint8_t word = userFunc(timePassed/1000000.0);
timePassed += periodMicros;
buff[i*2+0] = (word >> 0) & 0xff;
buff[i*2+1] = (word >> 1) & 0xff;
}
pa_simple_write(s, buff, 2*bufSize, &error);
this_thread::sleep_for(chrono::microseconds(bufSize*periodMicros));
}
}
Это устраняет проблему с процессором, но генерируемый им звук больше не является идеальной нотой.Похоже, что он немного выше, с ретро-ощущением.
Я хотел знать, как правильно использовать pa_simple
api без моего кода, пожирающего процессор.
Примечаниечто звук, генерируемый вторым кодом, не исправлен, даже если я изменил bufSize
на 1
и удалил строку sleep
.
Редактировать: Вот как я инициализировал соединение pulseaudio:
pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.channels = 1,
.rate = 44100
};
s = pa_simple_new(
NULL,
"SYNTH",
PA_STREAM_PLAYBACK,
NULL,
"Music",
&ss,
NULL,
NULL,
NULL
);