#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
|
|