Source file: /~heha/hsn/zqr.zip/src/zqr.h

#pragma once
/* Globale Projektdefinitionen
 * Hiesige Compiler-Einstellungen: Visual Studio 6, Service Pack 6
 * Include-Pfade:
	C:\Programme\MSVC\ddk3790\inc\wnet
	C:\Programme\MSVC\sdk6.0a\Include
	C:\Programme\MSVC\VC98\INCLUDE
 */

#define _WIN32_IE	0x0500
#define _WIN32_WINNT	0x0500
#define _CRT_SECURE_NO_WARNINGS	// ab MSVC2008
#define _NO_CRT_STDIO_INLINE	// ab MSVC2015
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>	// COMBOBOXEXITEM
#include <mmreg.h>	// WAVEFORMATEXTENSIBLE

#define T(x) TEXT(x)
#define elemof(x) (sizeof(x)/sizeof(*(x)))
#pragma intrinsic(memset,memcpy)

#if _MSC_VER < 1400
#undef Int32x32To64
// MSVC macht aus dieser (Nicht-Windows-)Funktion ein _allmul: unnötig!
__forceinline __int64 Int32x32To64(long x,long y) {
 __int64 r;
 _asm	mov	eax,x
 _asm	imul	y
 _asm	mov	dword ptr[r],eax
 _asm	mov	dword ptr[r+4],edx
 return r;
}

__forceinline __int64 llrint(double f) {
 __int64 i;
 _asm	fld	f
 _asm	fistp	i
 return i;
}
__forceinline __int64 llrint(float f) {
 __int64 i;
 _asm	fld	f
 _asm	fistp	i
 return i;
}
__forceinline int lrint(double f) {return int(llrint(f));}
__forceinline int lrint(float f) {return int(llrint(f));}
#define toInt(x) lrint(x)
#else
#define toInt(x) int(x)
#endif


// Je nachdem welches SDK und DDK man so einbindet und in welcher Reihenfolge
// fehlt mal dies und mal das:
//#if _MSC_VER < 1400
# ifndef __RPC__in
#  define __RPC__in
#  define __RPC__in_opt
#  define __RPC__in_ecount_full(x)
#  define __RPC__in_ecount_full_opt(x)
#  define __RPC__inout
#  define __RPC__inout_opt
#  define __RPC__deref_inout_opt
#  define __RPC__inout_ecount_full(x)
#  define __RPC__out
#  define __RPC__out_opt
#  define __RPC__deref_out_opt
#  define __RPC__out_ecount_full(x)
#  define __RPC__inout_ecount_full_opt(x)
#  define __RPC__out_ecount_part(x,y)
#  define __RPC__deref_out_opt_string
#  define __RPC_unique_pointer
#  define __RPC__out_ecount_full_string(x)
# endif
# ifndef PROPERTYKEY_DEFINED
struct PROPERTYKEY{GUID fmtid;DWORD pid;};
union REFPROPVARIANT;
# endif
# ifndef __in
#  define __in
#  define __in_bcount(x)
#  define __in_opt
#  define __in_ecount(x)
#  define __in_ecount_opt(x)
#  define __inout
#  define __out
#  define __out_opt
#  define __out_ecount(x)
#  define __out_awcount(x,y)
#  define __deref_opt_out
#  define __deref_out
#  define __deref_out_bcount(x)
#  define __reserved
# endif
//#endif

#ifdef _DEBUG
void _cdecl debugmsg(const TCHAR*msg,...);
#else
inline void _cdecl debugmsg(const TCHAR*msg,...) {}
#endif

const int MAXIN=8;	// Maximale Anzahl Mischkanäle (Eingänge)
const int MAXCH=8;	// Maximale Anzahl Audiokanäle (6 meint 5.1)

/*************************
 * Globale Konfiguration *
 *************************/
struct ACONFIG{		// Audio-Konfig
 char sel;	// Quellenauswahl, -1..127 (-1 = WAVE_MAPPER)
		// Windows XP: Ein Ausgang muss mit "Virtual Audio Cable Light" (VAC) zur Quelle gemacht werden.
		// Vista+: Mit WASAPI und Loopback-Funktion können Ausgänge „abgehört“ werden.
 BYTE nch_bits;	// Bit 2:0 = Audiokanäle 1..8
		// Bit 3 = AGC (Automatische Verstärkung = maximale Lautstärke) ungenutzt
		// Bit 5:4 = Bits: 0=8, 1=16, 2=24, 3=32
		// Bit 7:6 = ungenutzt
 BYTE getbytes() const {return (nch_bits>>4&3)+1;}	// Bytes pro Sample, 1..4
 BYTE getbits() const {return getbytes()<<3;}		// Bits pro Sample, 8..32
 void setbytes(BYTE b) {nch_bits=nch_bits&0xCF|(b-1)<<4;}
 void setbits(BYTE bits) {setbytes(bits>>3);}
 BYTE getspat() const {return nch_bits&7;}	// Art des Raumklangs, 0-basiert
 void setspat(BYTE c) {nch_bits=nch_bits&0xF8|c;}
 BYTE getchan() const {return getspat()+1;}	// Anzahl der Kanäle, zurzeit stets aufsteigend
 void setchan(BYTE c) {setspat(c-1);}
};

struct SRCCONFIG:public ACONFIG{
 char gain;	// Verstärkung vor dem Mixen, -120..120 entsprechend -20dB (×0.1) .. 20 dB (×10, logarithmisch)
 char panorama;	// -100 = Monosignal nach links, +100 = Monosignal nach rechts, 0 = Mitte. Nur bei Monosignal
 bool getAGC() const	{return (nch_bits>>3)&1;}
 void setAGC(BYTE action) {switch (action) {case false:nch_bits&=~8;break;case true:nch_bits|=8;break;case 2:nch_bits^=8;break;}}
};

struct DSTCONFIG:public ACONFIG{
 BYTE flags;	// Bit 0 = Ausgabe auf WaveOut-Device aktiv ("echoing")
		// Bit 1 = WASAPI (OLE/COM, ab Windows 8?) benutzen, sonst WINMM32 (Win32, ab Windows 3.1)
		// Bit 2 = Aufnahme läuft ("recording")
		// Bit 3 = Hauptfenster unsichtbar
		// Bit 4 = kurze (10 ms) Latenz, sonst 100 ms wie bisher
		// Bit 5 = 60 dB Anzeigeumfang, sonst 40 dB
		// Bit [7:6]: 0 = WAV, 1 = MP3, 2 = Vorbis
 BYTE rate;	// Gemeinsame Abtastrate in kSa/s, gerundet für 11,025, 22,05 und 44,1 kSa/s
 BYTE mp3min;	// Byterate für MP3- oder Vorbis-Kompression
 BYTE mp3max;
 DWORD getrate() const;
 BYTE getfileformat() const {return flags>>6;}
 void setfileformat(BYTE s) {flags=flags&0x3F|s<<6;}
 bool echoing() const {return flags&1;}
 void echoing(BYTE action) {switch (action) {case false:flags&=~1;break;case true:flags|=1;break;case 2:flags^=1;break;}}
 bool wasapi() const {return flags>>1&1;}
 void wasapi(BYTE action) {switch (action) {case false:flags&=~2;break;case true:flags|=2;break;case 2:flags^=2;break;}}
 bool recording() const {return flags>>2&1;}
 void recording(BYTE action) {switch (action) {case false:flags&=~4;break;case true:flags|=4;break;case 2:flags^=4;break;}}
 bool maininvis() const {return flags>>3&1;}
 void maininvis(BYTE action) {switch (action) {case false:flags&=~8;break;case true:flags|=8;break;case 2:flags^=8;break;}}
 int buftime() const {return flags&0x10?10:100;}	// Latenz der Echoausgabe in ms; 10 ms ist anscheinend die WASAPI-Voreinstellung
 int dbumfang() const {return flags&0x20?60:40;}	// Anzeigeumfang aller VU-Meter
 enum{
  nbuf=1,	// Anzahl der Puffer, zurzeit fest 1
 };
};

extern struct CONFIG{
 static bool load();
 static void save();
 static int NIN;	// Anzahl Mix-Kanäle (je nach Länge von "Config") beim Laden 1..4
 POINTS posMain,posSettings,posNotice;	// Fensterpositionen Hauptfenster, Einstellungs-Dialog und Notiz-Dialog
 DSTCONFIG z;		// 1 Zieldatei
 WORD hotkey[2];
 SRCCONFIG q[MAXIN];	// für bis zu 8 Quellen
}config;


void InitWaveFormat(WAVEFORMATEXTENSIBLE&,DWORD rate=0,BYTE channels=0,BYTE bits=0);

/************
 * save.cpp *
 ************/

int sprintDateTime(TCHAR*,int,const TCHAR*);
bool save_start();
bool save_stop();
void convertWav(const int*,unsigned,char*);

// Basisklasse für 3 Speicherziele (WAV/MP3/Vorbis)
class SAVE{
public:
 virtual bool okay() const=0;
 virtual bool start()=0;
 virtual bool put(const int*,unsigned) =0;	// Wird im Kontext eines Worker-Threads aufgerufen, aber in jedem Fall im Gänsemarsch
 virtual bool stop()=0;				// Längenangabe in Blocksamples!
 virtual ~SAVE() {};
 static void deleteall();	// Objekttöter
 static void newall();		// Objektfabrik
};

extern SAVE*save,*saveobj[3];
bool dllLoad(HINSTANCE&hLib,const TCHAR*name=0);
extern TCHAR currentfile[MAX_PATH];
extern bool newfile;
extern FILETIME starttime;		// Aufnahme-Startzeitpunkt
extern TCHAR file[MAX_PATH];	// eher ein Template mit Datums- und Uhrzeitfeld

/**********
 * WASAPI *
 **********/

bool ComboFillCallback(UINT i, bool indir, TCHAR*text, void*p);

namespace wasapi{
class RECORD{
 UINT idx;
 WAVEFORMATEXTENSIBLE*wf;
 typedef void(*cb_t)(const char*,DWORD,void*);	// Länge in Samples, nicht Bytes. Variabel, zum einfachen Mixen murks
 size_t wantsize;	// optimale Größe des Wave-Datenblocks in Samples (ohne ×2 für Stereo) zur Weiterverarbeitung, kleiner/größer geht aber auch
 cb_t cb;
 void*cbd;
 HANDLE hThread,hTerminate;
 static DWORD CALLBACK thread(void*);
 void thread();
 DWORD threadid;
 char*buffer;	// wantsize*wf->nBlockAlign Bytes
public:
 RECORD(UINT,WAVEFORMATEXTENSIBLE*,size_t,cb_t,void*);	// Der 2. Parameter muss bei start() gültig sein!!
 bool start();
 bool stop();
 bool alive();	// Thread beendet sich bei Fehler vorzeitig, v.a. bei gesperrtem Mikrofonzugriff
 ~RECORD();
};

UINT FillCombos(const HWND*h,const char*sel,COMBOBOXEXITEM*cbei);
}

/*********
 * Mixer *
 *********/

typedef void(*mixfunc_t)(int*mixbuf,const int*samples);
extern const mixfunc_t mixfunc[8][8];
// 1. Index: Zielkanalzahl und Lautsprecherkonfiguration
// 2. Index: Quellkanalzahl und Lautsprecherkonfiguration, bei 1 Kanal folgt <samples> die Panorama-Info (TODO)
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded