📄 spectral.c
字号:
DeleteObject(SelectObject(hdc, br));
ReleaseDC(canvas, hdc);
}
// PAINTCANVAS -- Refresh a display frame from its backing bitmap
static void paintCanvas(HWND canvas, HBITMAP image)
{
if (image != NULL) {
HDC hdc = GetDC(canvas), hdca;
HBITMAP oe;
RECT r;
int width, height;
GetClientRect(canvas, &r);
width = r.right - r.left;
height = r.bottom - r.top;
hdca = CreateCompatibleDC(hdc);
oe = SelectObject(hdca, image);
BitBlt(hdc, r.left + 1, r.top + 1, width - 2, height - 2, hdca, 1, 1, SRCCOPY);
SelectObject(hdca, oe);
DeleteDC(hdca);
ReleaseDC(canvas, hdc);
}
}
// CLEARBITMAP -- Clear a backing bitmap to a constant colour
static void clearBitmap(HWND canvas, HBITMAP image, COLORREF rgb)
{
HDC hdc = GetDC(canvas), hdca;
HBITMAP oe;
HBRUSH br;
HPEN pen;
RECT r;
hdca = CreateCompatibleDC(hdc);
GetClientRect(canvas, &r);
br = CreateSolidBrush(rgb);
br = SelectObject(hdca, br);
pen = CreatePen(PS_SOLID, 1, rgb);
pen = SelectObject(hdca, pen);
oe = SelectObject(hdca, image);
Rectangle(hdca, r.left, r.top, r.right, r.bottom);
DeleteObject(SelectObject(hdca, pen));
DeleteObject(SelectObject(hdca, br));
SelectObject(hdca, oe);
DeleteDC(hdca);
ReleaseDC(canvas, hdc);
}
// SPECTRALDLGPROC -- Spectral display dialogue procedure
BOOL CALLBACK spectralDlgProc(HWND hwnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
switch (nMessage) {
case WM_INITDIALOG:
hDlgSpectral = hwnd;
samps_in_buffer = 0;
epposx = sgposx = 0;
easel = weasel = NULL;
samples = (short *) malloc(fftsize * sizeof(short));
if (samples != NULL) {
pspectrum = (double *) malloc(nbands * sizeof(double));
if (pspectrum == NULL) {
free(samples);
samples = NULL;
} else {
sourceSpectrum = malloc(fftsize);
if (sourceSpectrum == NULL) {
free(samples);
samples = NULL;
free(pspectrum);
pspectrum = NULL;
}
}
}
CheckDlgButton(hwnd, IDC_SPEC_REALTIME, spectrumBarGraph);
CheckDlgButton(hwnd, IDC_SPEC_VOICEPRINT, spectrumVoicePrint);
CheckDlgButton(hwnd, IDC_SPEC_DISABLE, !(spectrumBarGraph || spectrumVoicePrint));
CheckDlgButton(hwnd, IDC_SPEC_TRANSMIT, spectrumTransmitOnly);
CheckDlgButton(hwnd, IDC_SPEC_RECEIVE, spectrumReceiveOnly);
CheckDlgButton(hwnd, IDC_SPEC_BOTH, !(spectrumTransmitOnly || spectrumReceiveOnly));
CheckDlgButton(hwnd, IDC_SPEC_ENV_RMS, !spectrumMaxEnergy);
CheckDlgButton(hwnd, IDC_SPEC_ENV_MAX, spectrumMaxEnergy);
{
HWND canvas = GetDlgItem(hwnd, IDC_SPEC_CHART);
HDC hdc = GetDC(canvas);
int width, height;
RECT r;
GetClientRect(canvas, &r);
width = r.right - r.left;
height = r.bottom - r.top;
easel = CreateCompatibleBitmap(hdc, width, height);
ReleaseDC(canvas, hdc);
clearBitmap(canvas, easel, RGB(128, 128, 128));
canvas = GetDlgItem(hwnd, IDC_SPEC_ENVELOPE);
hdc = GetDC(canvas);
GetClientRect(canvas, &r);
width = r.right - r.left;
height = r.bottom - r.top;
weasel = CreateCompatibleBitmap(hdc, width, height);
ReleaseDC(canvas, hdc);
clearBitmap(canvas, weasel, RGB(0, 0, 0));
}
spectrumChanged = TRUE;
return TRUE;
case WM_CLOSE:
DestroyWindow(hwnd);
return TRUE;
case WM_DESTROY:
if (samples != NULL) {
free(samples);
samples = NULL;
}
if (sourceSpectrum != NULL) {
free(sourceSpectrum);
sourceSpectrum = NULL;
}
if (pspectrum != NULL) {
free(pspectrum);
pspectrum = NULL;
}
if (easel != NULL) {
DeleteObject(easel);
easel = NULL;
}
if (weasel != NULL) {
DeleteObject(weasel);
weasel = NULL;
}
spectrumEnd();
hDlgSpectral = NULL;
return 0;
case WM_PAINT:
InvalidateRect(GetDlgItem(hwnd, IDC_SPEC_CHART), NULL, FALSE);
InvalidateRect(GetDlgItem(hwnd, IDC_SPEC_ENVELOPE), NULL, FALSE);
paintCanvas(GetDlgItem(hwnd, IDC_SPEC_CHART), easel);
paintCanvas(GetDlgItem(hwnd, IDC_SPEC_ENVELOPE), weasel);
break;
case WM_UPDATE_SPECTRUM:
#ifdef _DEBUG
{ char s[20];
sprintf(s, "P=%.2f E=%d", escale, aEnergy);
SetDlgItemText(hwnd, IDC_SPEC_SCALE, s);
}
#endif
paintEnergy(GetDlgItem(hwnd, IDC_SPEC_ENVELOPE));
paintSpectrum(GetDlgItem(hwnd, IDC_SPEC_CHART));
paintCanvas(GetDlgItem(hwnd, IDC_SPEC_CHART), easel);
paintCanvas(GetDlgItem(hwnd, IDC_SPEC_ENVELOPE), weasel);
break;
case WM_COMMAND:
switch ((short) WM_COMMAND_ID(wParam)) {
case IDOK:
PostMessage(hwnd, WM_CLOSE, 0, 0L);
break;
case ID_HELP:
displayHelpTopic(IDS_HELP_SPECTRUM);
break;
case IDC_SPEC_REALTIME:
case IDC_SPEC_VOICEPRINT:
case IDC_SPEC_DISABLE:
spectrumBarGraph = IsDlgButtonChecked(hwnd, IDC_SPEC_REALTIME);
spectrumVoicePrint = IsDlgButtonChecked(hwnd, IDC_SPEC_VOICEPRINT);
spectrumChanged = TRUE;
clearCanvas(GetDlgItem(hwnd, IDC_SPEC_CHART), RGB(128, 128, 128));
sgposx = epposx;
disableShown = FALSE;
if (!(spectrumBarGraph || spectrumVoicePrint)) {
paintSpectrum(GetDlgItem(hwnd, IDC_SPEC_CHART));
}
break;
case IDC_SPEC_TRANSMIT:
case IDC_SPEC_RECEIVE:
case IDC_SPEC_BOTH:
spectrumTransmitOnly = IsDlgButtonChecked(hwnd, IDC_SPEC_TRANSMIT);
spectrumReceiveOnly = IsDlgButtonChecked(hwnd, IDC_SPEC_RECEIVE);
break;
case IDC_SPEC_ENV_RMS:
case IDC_SPEC_ENV_MAX:
spectrumMaxEnergy = IsDlgButtonChecked(hwnd, IDC_SPEC_ENV_MAX);
break;
}
}
return FALSE;
}
// SPECTRALDIALOGUE -- Spectral display dialogue
VOID spectralDialogue(HWND hwndParent)
{
if (hDlgSpectral == NULL) {
hDlgSpectral = CreateDialog(hInst, MAKEINTRESOURCE(IDD_SPECTRUM),
hwndParent, spectralDlgProc);
}
}
/* ENERGY -- Calculate RMS and maximum energy of samples in this
buffer for envelope display. */
static void energy(short *samples, int nsamples, double *rms, double *emax)
{
long i;
double alevel = 0, mlevel = 0;
for (i = 0; i < nsamples; i++) {
int samp = samples[i];
if (samp < 0) {
if (samp == -32768) {
samp = -32767;
}
samp = -samp;
}
alevel += ((double) samp) * samp;
if (samp > mlevel) {
mlevel = samp;
}
}
alevel = sqrt(alevel / nsamples);
#ifdef _DEBUG
aEnergy = (int) alevel;
#endif
if (alevel < noiseFloor) {
alevel = 0.0;
} else {
alevel -= noiseFloor;
}
if (logEnergy) {
*rms = ((log(((double) alevel) + M_E) - 1) / (log(32767.0 + M_E) - 1));
*emax = ((log(((double) mlevel) + M_E) - 1) / (log(32767.0 + M_E) - 1));
} else {
*rms = alevel / 32767.0;
*emax = mlevel / 32767.0;
}
}
/* STORESAMPLE -- Store next sample into buffer, updating spectrum
when it's full. */
static void storeSample(short samp, BOOL isInput)
{
sourceSpectrum[samps_in_buffer] = isInput;
samples[samps_in_buffer++] = samp;
if (samps_in_buffer >= fftsize) {
DWORD tc = GetTickCount();
// Update average energy (0 to 1) of samples in buffer
energy(samples, samps_in_buffer, &cEnergy, &mEnergy);
ceColour = sourceSpectrum[samps_in_buffer -1] ? RGB(0, 0, 255) : RGB(0, 255, 0);
// Update power spectrum if it's being displayed
if (spectrumBarGraph || spectrumVoicePrint) {
pscale = spectrum(samples, samps_in_buffer, pspectrum, nbands, 0.0);
if (pscale > escale) {
// New maximum power--set as top of scale
escale = pscale;
} else {
/* Otherwise exponentially smooth the scale factor
for a smooth adaptive gain adjustment. */
escale = escale + PSMOOTH * (pscale - escale);
}
}
samps_in_buffer = 0;
if (!paintingSpectrum && ((nextSpectrumTime == 0) || (tc < nextSpectrumTime) ||
(tc > (nextSpectrumTime + SPECTRUM_INTERVAL)))) {
nextSpectrumTime = tc;
PostMessage(hDlgSpectral, WM_UPDATE_SPECTRUM, 0, 0);
}
}
}
/* SPECTRUMUPDATE -- Receive latest batch of audio samples and
update the spectrum display, if necessary.
If align == 0 and bytesec == 8000, the samples
are assumed to already be in mu-law format. */
void spectrumUpdate(LPSTR buffer, WORD buflen, DWORD channels,
DWORD rate, DWORD bytesec, WORD align, BOOL isInput)
{
// Discard buffer if we're not monitoring this direction
if ((isInput && spectrumTransmitOnly) ||
((!isInput) && spectrumReceiveOnly)) {
return;
}
/* The job of the following code is to transform, if necessary,
the received samples into 16 bit signed form and add them to
the FFT array. */
if ((hDlgSpectral != NULL) && (samples != NULL)) {
if (align == 2) {
int i;
for (i = 0; i < buflen / align; i++) {
storeSample((short) (((WORD FAR *) buffer)[i]), isInput);
}
} else { // align == 1 or align == 0
int i;
for (i = 0; i < buflen; i++) {
/* This looks inefficient--it should just transform the 8 bit
sample directly to 16 bit, but after all it's only two
array accesses, which are trivial compared to the number
of FFTs we're doing here. */
storeSample(audio_u2s((isInput || (align == 0)) ? (((BYTE FAR *) buffer)[i]) : audio_c2u((((BYTE FAR *) buffer)[i]))), isInput);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -