Składową stała najprościej obliczysz uśredniając wartości wszystkich próbek (suma/ilość).
Do uśredniania warto przepuścić próbki przez np. hanning window filter, by łagownie odciąć próbki z poczatku i końca bufora, które zazwyzaj nie zaczynają/kończą się w zerze.
Natomiast przejścia przez zero wykrywasz programowym przerzutnikiem schmitta, który zmienia stan dopiero gdy sygnał wejściowy przekroczy jakiś dodatni lub ujemny poziom.
Tu masz przykład najprostszego miernika częstotliwości, w C
#include <windows.h>
#include <conio.h>
#pragma comment(lib, "winmm")
#define RECORD_TIME 1000 // sekunda
short buffer[441*RECORD_TIME/10];
int main()
{
static WAVEFORMATEX format = {WAVE_FORMAT_PCM,1,44100,88200,2,16,0};
HWAVEIN hSound;
HANDLE hEvent = CreateEvent(0,0,0,0);
if (!waveInOpen(&hSound, WAVE_MAPPER, &format, (DWORD_PTR)hEvent, 0, CALLBACK_EVENT))
{
WAVEHDR hdr = {(LPSTR)buffer, sizeof(buffer), 0, 0, WHDR_BEGINLOOP|WHDR_ENDLOOP, 0, 0};
WaitForSingleObject(hEvent, RECORD_TIME/10);
if (!waveInPrepareHeader(hSound, &hdr, sizeof(hdr)))
{
int a, state=0, count;
waveInStart(hSound);
while (!_kbhit() && !waveInAddBuffer(hSound, &hdr, sizeof(hdr)))
{
short peak = 0;
WaitForSingleObject(hEvent, RECORD_TIME+(RECORD_TIME/10));
count = 0;
for (a=0; a<(sizeof(buffer)/2); a++)
{
if (buffer[a] > peak) peak = buffer[a];
if (!state && buffer[a]>300)
{
state = 1;
count++;
}
else if (state && buffer[a]<-300)
{
state = 0;
}
}
printf("frequency: %d Hz peak: %d\n", (count*1000)/RECORD_TIME, peak);
}
waveInUnprepareHeader(hSound, &hdr, sizeof(hdr));
}
waveInClose(hSound);
}
CloseHandle(hEvent);
return 0;
}
Wartość 300 określa próg czułości, i powinna być większa od poziomu szumu toru dźwiękowego, oraz szumu tła odbieranego przez mikrofon. Nie ma tutaj usuwania składowej stałej, ani filtra okienka (np. hanning), bo w tak prostym mierniku filtr okna by spowodował przekłamanie wyniku, zmniejszajac ilość przejść przez zero w jednostce czasu.