/* Original name: Starting GDIplus
* Modified for minimum executable size by Henrik Haftmann
* Ownerdraw buttons are used inside the resource for 2 canvases
* Made for MSVC6, newer versions of Visual Studio need modifications
*/
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <objbase.h> // needed for DEFINE_GUID inside gdiplus.h
#include <gdiplus.h>
#include <math.h>
#include <stdio.h>
#include <tchar.h>
// Don't forget to remove /GZ compiler option for NODEFAULTLIB!
#pragma comment(linker,"/NODEFAULTLIB /OPT:nowin98") // no msvcrt.lib, reduce alignment space
#pragma comment(linker,"/LARGEADDRESSAWARE /RELEASE") // allow 3 GB address space, generate checksum
#pragma intrinsic(memset)
#define T(x) TEXT(x) // shorter macro - may conflict with template definitions
#define elemof(x) (sizeof(x)/sizeof(*(x))) // number of array elements
HINSTANCE HInstance; // global instance handle, needed for LoadIcon
TCHAR filename[260];
extern "C" void _cdecl _fltused() {} // needed by MSVC6 when float is used (by gdiplus.h)
HWND hMainWnd;
const float M_PI=3.1415926535F;
// ATmega8-kompatibler Kode
static struct Sintab{
char a[256];
void init() {
for (int i=0; i<256; i++) a[i]=char(floorf(0.5F+sinf(i*M_PI*2/256)*122));
}
inline char operator[](BYTE i) const {return a[i];}
}sintab;
inline char scale(char sa) {return sa;} // zum Experimentieren!!
static struct Window{ // Hann-Fenster (cos²-Fenster), liefert 0..256
WORD*a;
void init(int len) {
if (a) delete[] a;
a=new WORD[len];
for (int i=0; i<len; i++) a[i]=WORD(floorf(0.5F+(1-cosf(i*M_PI*2/len))*128)); // über Doppelwinkelformel
}
Window():a(0) {}
~Window() {if (a) delete[] a;}
inline WORD operator[](int i) const {return a[i];}
}window;
// Spektralleistung (auf Linie f256)
int power(char*samples, int len, int f256) {
int sinval=0,cosval=0,angle=0;
for (int i=0; i<len; i++) {
char sa=scale(samples[i])*window[i]>>8; // lpm,mulsu
sinval+=sintab[BYTE(angle>>8)]*sa; // muls,add3
cosval+=sintab[BYTE((angle>>8)+64)]*sa; // muls,add3
angle+=f256; // add3
}
sinval/=len; cosval/=len;
sinval/=122/2/2; cosval/=122/2/2; // Sinus-Maximalwert, Verlust durch Fensterung, Annahme: Halbe Aussteuerung
sinval*=sinval;
cosval*=cosval;
return cosval+sinval; // Vektorbetrag-Quadrat
}
// Gesamtleistung
int power(char*samples, int len) {
int q=0; // Quadrate
for (int i=0; i<len; i++) {
char sa=scale(samples[i])*window[i]>>8;// lpm,mulsu
q+=sa*sa; // muls,add3
}
q/=len; // jetzt passt das Ergebnis in 14 Bit
q*=2; // Verlust durch Fensterung
return q;
}
const unsigned WM_DtmfResult=WM_USER+3;
struct ScanDTMF{
struct{
BYTE i; // 1 Byte RAM
int sinval[7],cosval[7]; // je 24 Bit = 3 Byte, macht 45 Byte RAM
unsigned q;
}v;
WORD angle[7]; // 14 Byte RAM
WORD f256[7]; // 14 Byte Flash
ScanDTMF() {init();}
void init() {memset(&v,0,sizeof v);}
void onSample(char sa) {
short saw=sa*window[v.i]; // lpm,mulsu
sa=saw>>8;
if (LOBYTE(saw)>=0x80) ++sa; // runden
for (int k=0; k<7; k++) { // im AVR ausgerollt
BYTE arg=BYTE(angle[k]>>8);
v.sinval[k]+=sintab[arg]*sa; // lpm,muls,add3
v.cosval[k]+=sintab[BYTE(arg+64)]*sa;// lpm,muls,add3
angle[k]+=f256[k]; // subi, sbci
}
v.q+=sa*sa; // muls, add3
if (!++v.i) {
WORD*result=new WORD[8];
for (int k=0; k<7; k++) {
char s=v.sinval[k]>>12; // >>8 wegen 256 Samples, >>8 wegen Sinustabelle
char c=v.cosval[k]>>12;
result[k]=s*s+c*c; // Vektorbetrag-Quadrat
}
result[7]=v.q>>4; // >>8 wegen 256 Samples
init();
if (!PostMessage(hMainWnd,WM_DtmfResult,0,(LPARAM)result)) delete[] result;
}
}
};
// Ende ATmega8-Kode
struct Detector{
HWAVEOUT hwo;
HMMIO hFile;
LONG datasize;
LONG blocklen;
WAVEHDR hdr[2];
union{
char*s;
WAVEFORMATEX*wf;
}wf;
int start() {
if (hwo) return 0;
MMIOINFO ioWav;
ZeroMemory(&ioWav,sizeof ioWav);
// static const WAVEFORMATEX wf={WAVE_FORMAT_PCM,1,8000,8000,1,8};
hFile=mmioOpen(filename,0,MMIO_READ|MMIO_ALLOCBUF);
if (!hFile) return-1;
MMCKINFO ckWav;
ckWav.fccType=mmioFOURCC('W','A','V','E');
if (mmioDescend(hFile,&ckWav,0,MMIO_FINDRIFF)) {
mmioClose(hFile,0); hFile=0;
return-2;
}
MMCKINFO ckFmt;
ckFmt.fccType=mmioFOURCC('f','m','t',' ');
if (mmioDescend(hFile,&ckFmt,&ckWav,MMIO_FINDCHUNK)) {
mmioClose(hFile,0); hFile=0;
return-3;
}
LONG len=ckFmt.cksize;
wf.s=new char[len];
if (mmioRead(hFile,wf.s,len)!=len) {
delete[] wf.s;
mmioClose(hFile,0); hFile=0;
return-4;
}
mmioAscend(hFile,&ckFmt,0);
ckFmt.ckid=mmioFOURCC('d','a','t','a');
if (mmioDescend(hFile,&ckFmt,&ckWav,MMIO_FINDCHUNK)) {
delete[] wf.s;
mmioClose(hFile,0); hFile=0;
return-5;
}
datasize=ckFmt.cksize;
blocklen=wf.wf->nAvgBytesPerSec/20>>2<<2; // 50 ms, ganze DWORDs
// blocklen=256;
PostMessage(hMainWnd,WM_USER+1,datasize,blocklen);
if (waveOutOpen(&hwo,WAVE_MAPPER,wf.wf,(DWORD_PTR)waveOutProcS,(DWORD_PTR)this,CALLBACK_FUNCTION)) {
hwo=0;
delete[] wf.s;
mmioClose(hFile,0); hFile=0;
return-6;
}
// this->hwo wird netterweise gesetzt BEVOR der Callback aufgerufen wird? Nee!
ZeroMemory(hdr,sizeof hdr);
for (int i=0; i<elemof(hdr); i++) {
WAVEHDR&wh=hdr[i];
wh.lpData=new char[blocklen];
wh.dwBufferLength=blocklen;
wh.dwUser=(DWORD_PTR)this;
waveOutPrepareHeader(hwo,&wh,sizeof wh);
sendBuffer(wh);
}
return 0;
}
void end() {
if (!hwo) return;
waveOutReset(hwo);
for (int i=elemof(hdr); --i>=0;) {
WAVEHDR&wh=hdr[i];
waveOutUnprepareHeader(hwo,&wh,sizeof wh);
delete[] wh.lpData;
}
waveOutClose(hwo);
hwo=0;
mmioClose(hFile,0); hFile=0;
delete[] wf.s;
}
static void CALLBACK waveOutProcS(HWAVEOUT hwo,UINT msg, DWORD_PTR dwInst, DWORD_PTR dwParam1, DWORD_PTR) {
((Detector*)dwInst)->hwo=hwo;
((Detector*)dwInst)->waveOutProc(msg,*(WAVEHDR*)dwParam1);
}
void sendBuffer(WAVEHDR&wh) {
LONG len=datasize; if (len>blocklen) len=blocklen;
if (mmioRead(hFile,wh.lpData,len)==len) {
wh.dwBufferLength=len;
waveOutWrite(hwo,&wh,sizeof wh);
datasize-=len;
}
}
void waveOutProc(UINT msg, WAVEHDR&wh) {
switch (msg) {
case WOM_DONE: {
PostMessage(hMainWnd,WM_USER+2,wh.dwBufferLength,(LPARAM)mkInt8Wave(wh));
if (wh.dwBufferLength) sendBuffer(wh);
}break;
}
}
char*mkInt8Wave(WAVEHDR&wh) {
int n=wf.wf->nAvgBytesPerSec/wf.wf->nSamplesPerSec; // Bytes pro Sample
int samples=wh.dwBufferLength/n;
char*ret=new char[samples];
for (int i=0; i<samples; i++) {
char sa;
if (wf.wf->wBitsPerSample==8) sa=wh.lpData[i*n]-0x80;
else sa=wh.lpData[i*n+1]; // Nur linken Kanal nehmen, rechts ignorieren
ret[i]=sa;
}
return ret;
}
};
struct Record{
HWAVEIN hwi;
LONG blocklen;
WAVEHDR hdr[2];
WAVEFORMATEX wf;
int start() {
if (hwi) return 0;
wf.wFormatTag=WAVE_FORMAT_PCM;
wf.nChannels=1;
wf.wBitsPerSample=16;
wf.nSamplesPerSec=8000;
wf.nBlockAlign=((wf.wBitsPerSample+7)>>3)*wf.nChannels;
wf.nAvgBytesPerSec=wf.nSamplesPerSec*wf.nBlockAlign;
wf.cbSize=0;
blocklen=wf.nAvgBytesPerSec/20; // 50 ms
PostMessage(hMainWnd,WM_USER+1,0,blocklen);
if (waveInOpen(&hwi,WAVE_MAPPER,&wf,(DWORD_PTR)waveInProcS,(DWORD_PTR)this,CALLBACK_FUNCTION)) {
hwi=0;
return-7;
}
ZeroMemory(hdr,sizeof hdr);
for (int i=0; i<elemof(hdr); i++) {
WAVEHDR&wh=hdr[i];
wh.lpData=new char[blocklen];
wh.dwBufferLength=blocklen;
wh.dwUser=(DWORD_PTR)this;
waveInPrepareHeader(hwi,&wh,sizeof wh);
waveInAddBuffer(hwi,&wh,sizeof wh);
}
waveInStart(hwi);
return 0;
}
void end() {
if (!hwi) return;
wf.wFormatTag=0;
waveInReset(hwi);
for (int i=elemof(hdr); --i>=0;) {
WAVEHDR&wh=hdr[i];
waveInUnprepareHeader(hwi,&wh,sizeof wh);
delete[] wh.lpData;
}
waveInClose(hwi);
hwi=0;
}
static void CALLBACK waveInProcS(HWAVEIN hwi,UINT msg, DWORD_PTR dwInst, DWORD_PTR dwParam1, DWORD_PTR) {
((Record*)dwInst)->hwi=hwi;
((Record*)dwInst)->waveInProc(msg,*(WAVEHDR*)dwParam1);
}
void waveInProc(UINT msg, WAVEHDR&wh) {
switch (msg) {
case WIM_DATA: {
PostMessage(hMainWnd,WM_USER+2,wh.dwBufferLength/wf.nBlockAlign,(LPARAM)mkInt8Wave(wh));
if (wh.dwBytesRecorded && wf.wFormatTag) waveInAddBuffer(hwi,&wh,sizeof wh);
}break;
}
}
char*mkInt8Wave(WAVEHDR&wh) {
int n=wf.nAvgBytesPerSec/wf.nSamplesPerSec; // Bytes pro Sample
int samples=wh.dwBytesRecorded/n;
char*ret=new char[samples];
for (int i=0; i<samples; i++) {
char sa;
if (wf.wBitsPerSample==8) sa=wh.lpData[i*n]-0x80;
else sa=*(short*)(wh.lpData+i*n)>>4; // Nur linken Kanal nehmen, rechts ignorieren
ret[i]=sa;
}
return ret;
}
};
static TCHAR MBoxTitle[64];
static int vMBox(HWND wnd, UINT_PTR id, UINT sty, va_list va) {
TCHAR s[256],t[256];
LoadString(0,id,t,elemof(t));
_sntprintf(s,elemof(s),t,va);
return MessageBox(wnd,s,MBoxTitle,sty);
}
static int _cdecl MBox(HWND wnd, UINT_PTR id, UINT sty, ...) {
va_list va;
va_start(va,sty);
int ret=vMBox(wnd,id,sty,va);
va_end(va);
return ret;
}
struct Ofn:public OPENFILENAME {
TCHAR filter[64];
Ofn(HWND wnd,PTSTR filename,UINT filenamelen,UINT filterid, DWORD flags=OFN_HIDEREADONLY|OFN_FILEMUSTEXIST) {
ZeroMemory(this,sizeof(OPENFILENAME));
lStructSize=sizeof(OPENFILENAME);
Flags=flags;
hwndOwner=wnd;
lpstrFile=filename;
nMaxFile=filenamelen;
filter[LoadString(0,filterid,filter,elemof(filter)-1)+1]=0; // Double-zero termination
lpstrFilter=filter;
}
bool GetOpenFileName() {return !!::GetOpenFileName(this);}
bool GetSaveFileName() {return !!::GetSaveFileName(this);}
};
static Detector detector;
static Record record;
static int bild;
static bool clipdeco;
static ScanDTMF scandtmf;
static BYTE bggray=192;
static BOOL CALLBACK StartingGDIPlusDlg(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG: { // when dialog is populated with all child windows
SetClassLong(Wnd,GCL_HICON,(LONG)LoadIcon(HInstance,MAKEINTRESOURCE(1)));
hMainWnd=Wnd;
GetWindowText(Wnd,MBoxTitle,elemof(MBoxTitle));
sintab.init();
window.init(256);
}return TRUE; // let dialog manager set focus to first focusable element (here: OK button)
case WM_COMMAND: switch (wParam) {
case 16: MBox(Wnd,16,MB_OK); break;
case 45: // load DTMF
case 46: { // load CLIP
Ofn ofn(Wnd,filename,elemof(filename),45);
if (ofn.GetOpenFileName()) {
bild=0;
clipdeco=wParam==46;
int ret=detector.start();
if (ret<0) MBox(Wnd,16-ret,MB_OK);
else{
static const int fs[8]={697,770,852,941,1209,1336,1477};
for (int k=0; k<elemof(fs); k++)
scandtmf.f256[k]=WORD((fs[k]<<16)/detector.wf.wf->nSamplesPerSec);
scandtmf.init();
}
}
}break;
case 47: {
int ret=record.start();
if (ret<0) MBox(Wnd,16-ret,MB_OK);
else{
static const int fs[8]={697,770,852,941,1209,1336,1477};
for (int k=0; k<elemof(fs); k++)
scandtmf.f256[k]=WORD((fs[k]<<16)/record.wf.nSamplesPerSec);
scandtmf.init();
}
}break;
case 48: {
record.end();
SendDlgItemMessage(Wnd,12,PBM_SETMARQUEE,0,0);
}break;
case IDCANCEL:
case IDOK: EndDialog(Wnd,wParam); break; // Both cases use same EndDialog()
}break;
case WM_DRAWITEM: { // when ownerdraw elements need to repaint
DRAWITEMSTRUCT*dis=(DRAWITEMSTRUCT*)lParam; // Let compiler remove unnecessary assignments
}break;
case WM_USER+1: { // wParam = Dateilänge, lParam=Fensterlänge
HWND hProgress=GetDlgItem(Wnd,12);
if (wParam) {
SendMessage(hProgress,PBM_SETRANGE32,0,wParam);
SendMessage(hProgress,PBM_SETSTEP,1,0);
SendMessage(hProgress,PBM_SETPOS,0,0);
}else{
SetWindowLong(hProgress,GWL_STYLE,GetWindowLong(hProgress,GWL_STYLE)|PBS_MARQUEE);
SendMessage(hProgress,PBM_SETMARQUEE,1,0);
}
}break;
case WM_USER+2: { // wParam = Chunklänge
if (wParam) {
SendDlgItemMessage(Wnd,12,PBM_DELTAPOS,wParam,0);
char*int8buf=(char*)lParam;
using namespace Gdiplus;
{
HWND hCanvas=GetDlgItem(Wnd,10);
HDC dc=GetDC(hCanvas);
Graphics g(dc);
int z=rand();
Pen pen(Color(255,z&1?255:0,z&2?255:0,z&4?255:0));
Point pt(0,128-int8buf[0]);
for (int i=1; i<(int)wParam; i++) {
Point pt2(i*2,128-int8buf[i]);
g.DrawLine(&pen,pt,pt2);
pt=pt2;
}
ReleaseDC(hCanvas,dc);
}
for (int i=0; i<(int)wParam; i++) scandtmf.onSample(int8buf[i]);
delete[] int8buf;
}
else detector.end();
}break;
case WM_DtmfResult: {
WORD*data=(WORD*)lParam;
using namespace Gdiplus;
HWND hCanvas=GetDlgItem(Wnd,11);
HDC dc=GetDC(hCanvas);
Graphics g(dc);
g.TranslateTransform(45.0F*(bild%20),32.0F*(bild/20));
SolidBrush bkgnd(Color(255,bggray,bggray,bggray));
g.FillRectangle(&bkgnd,0,0,45,32);
Pen pen1(Color(255,0,255,0),3); // Tiefe Frequenz
Pen pen2(Color(255,0,255,255),3); // Hohe Frequenz
Pen pen3(Color(255,255,0,255),3); // Summenleistung
Pen*pens[]={&pen1,&pen1,&pen1,&pen1,&pen2,&pen2,&pen2,&pen3};
for (int k=0; k<8; k++) {
WORD p=data[k];
g.DrawLine(pens[k],0.0F,2.0F+k*4,logf(float(p+1))*2+1,2.0F+k*4);
}
char det=0;
for(int kk=0; kk<7; kk++) {
float relpower=float(data[kk])/float(data[7]);
if (relpower>=0.25F && relpower<1.0F) det|=1<<kk; // muss ungefähr die Hälfte der Summenleistung sein
}
const char dets[]={0x11,0x21,0x41,0x12,0x22,0x42,0x14,0x24,0x44,0x18,0x28,0x48};
const char zifs[]="123456789*0#";
char*p=(char*)memchr(dets,det,12);
if (p) det=zifs[p-dets]; else det=0;
if (det) {
wchar_t c=det;
Font font(L"Arial",14);
PointF origin(5.0F,5.0F);
SolidBrush brush(Color(255,0,0,0));
g.DrawString(&c,1,&font,origin,&brush);
}
if (++bild==20*13) {bild=0; bggray^=20;}
ReleaseDC(hCanvas,dc);
delete[]data;
}break;
}
return FALSE;
}
int WINAPI WinMainCRTStartup(){ // no WinMain entry due to NODEFAULTLIB
InitCommonControls();
ULONG_PTR gdiplusToken;
HInstance=GetModuleHandle(0);
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,0);
DialogBox(HInstance,MAKEINTRESOURCE(1),0,StartingGDIPlusDlg);
Gdiplus::GdiplusShutdown(gdiplusToken);
ExitProcess(0);
}
Detected encoding: ANSI (CP1252) | 4
|
|