Archiv der Kategorie: C++

Microsoft Visual C++ : How to call WinMain() from a console apps main()-method / Wie man die WinMain-Methode von einer Konsolenanwendung aus aufruft

Problem

Eine C++ Anwendung hat als Konsolenanwendung den Einstiegspunkt

int main(void) {...}

aber als Win32-Anwendung den Einstiegspunkt

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)  {...}

Es wird nach einer Möglichkeit gesucht, die WinMain-Methode von einer Konsolen-Anwendung aus aufzurufen, um eine Hauptfenster in der Konsolenanwendung zu generieren.

Ansatz

MSDN definiert die WinMain()-Methode folgendermaßen:

  • hInstance ist ein Element, das als „Handle für eine Instanz“ oder „Handle für ein Modul“ bezeichnet wird. Das Betriebssystem identifiziert mithilfe dieses Werts die ausführbare Datei (EXE), wenn diese in den Arbeitsspeicher geladen wird. Das Instanzhandle wird für bestimmte Windows-Funktionen benötigt—z. B. um Symbole oder Bitmaps zu laden.
  • hPrevInstance hat keine Bedeutung. Es wurde in 16-Bit-Windows verwendet, es ist aber jetzt stets 0 (null).
  • pCmdLine enthält die Befehlszeilenargumente als Unicode-Zeichenfolge.
  • nCmdShow ist ein Flag, das angibt, ob das Hauptanwendungsfenster minimiert, maximiert oder in Normalgröße angezeigt wird.

Die WinMain()-Methode kann von der main()-Anwendung aufgerufen werden, wenn man ein hInstance Handle bekommt. Dies geht folgermaßen:

GetModuleHandle(NULL)

Lösung – Solution

// HelloWorld.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <windows.h> 

// Das hier braucht man nur wenn man die test.wav abspielen will
//#pragma comment(lib,"winmm.lib")  //für MSV C++   

const char g_szClassName[] = "myWindowClass";

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CLOSE:
		DestroyWindow(hwnd);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc;
	HWND hwnd;
	MSG Msg;

	//Step 1: Registering the Window Class
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = (LPCWSTR) g_szClassName;
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassEx(&wc))
	{
		MessageBox(NULL, L"Window Registration Failed!", L"Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	// Step 2: Creating the Window
	hwnd = CreateWindowEx(
		WS_EX_CLIENTEDGE,
		(LPCWSTR) g_szClassName,
		L"Eine Mischung aus Console und Window App",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
		NULL, NULL, hInstance, NULL);

	if (hwnd == NULL)
	{
		MessageBox(NULL, L"Window Creation Failed!", L"Error!",
			MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	// Step 3: The Message Loop
	while (GetMessage(&Msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
	return Msg.wParam;
}


int main()
{
	// Das hier spielt eine Datei test.wav im gleichen Verzeichnis
	//PlaySound(L"test.wav", NULL, SND_ASYNC);
	
	WinMain(GetModuleHandle(NULL), 0, 0, 1);

	printf("Se hams Fenster geschlossen!");
	getchar();

	return 0;
}

C++ und Visual Studio 2015 : Standard Libraries not found: stdio.h / cerrno.h / float.h / math.h … not found | Simple „Hello world!“ program not working

Problem

You have installed Visual Studio 2015 (Community Edition) and you are unable to compile a simple „Hello World!“ program using C++.

Nach der Installation von Visual Studio 2015 (Community Edition) lässt sich nicht mal ein simples „Hello World!“ Programm erstellen.

Analysis – Analyse

According to Microsofts article https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ the headers, sources, and libraries are now distributed as part of a separate Universal CRT SDK. This SDK is included with Visual Studio; it is installed by default to C:\Program Files (x86)\Windows Kits\10. The debug ucrtbased.dll is also included as part of this SDK and is installed to the system directory.

Microsoft erwähnt in seinem Artikel https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/, dass die Header-Bibliotheken als Teil eines seperaten universellen C-Runtime SDK ausgefliefert werden, welches Standardmäßig mit Visual Studio 2015 in C:\Program Files (x86)\Windows Kits\10 installiert wird. Die ucrtbased.dll-Datei, welche auch Teil des SDKs ist, wird in das Systemverzeichnis kopiert.

Lösung – Solution

Der Bildschirm nach dem Kompilieren (orange) – Visual Studio 2015 findet 460 Fehler.
Screenshot after the compilation progress (orange) – Visual Studio 2015 is reporting 460 Errors.

errors

Rot: Um das Problem zu lösen -> Rechtsklick auf Projekt -> „Eigenschaften“ wählen.
Red: To solve the problem rightclick the project  and select „Properties“.

Library Path: C:\Program Files\Windows Kits\10\Lib\10.0.10150.0\ucrt\x86

pfad1

Danach müssen wir analog dazu den Include-Pfad (wieder mit einem Projekt-Rechtsklick -> Eigenschaften) einrichten.

After that we have to configure a second path to the Include-Directory in the same way (Rightclick project -> properties)

Include Path: C:\Program Files\Windows Kits\10\Include\10.0.10150.0\ucrt

path2

Nun kann man trotz der Anzeigen von Fehlern das Projekt einfach kompilieren, nach dem ersten Kompilier- oder Erstellvorgang sind die Fehlermeldungen in der Regel verschwunden.

Now you can hit the Run-Button / Recreate the project / Recompile it. After that the other errors should disapear.

helloworldcpp

VST Plugins in C++ mit WDL-OL: Signalverarbeitung durch INSERT-Effekte und ihre Auswirkungen

Intention

In diesem Artikel dokumentiere ich meine ersten Erkenntnisse, die ich als Informatiker, Musiker und Cubase-Benutzer bei der Entwicklung von VST Plugins in C++ mache. Der Artikel wirkt daher sehr Ich-bezogen, da ich mich auf meinen eigenen Explorations-Lerntyp konzentriere. Ich bin allerdings kein Egozentriker :-/ …

Vorwort

Als musik- und programmierbegeisterterter DAW-Nutzer (ich bin Cubase Fan), fehlt einem oft noch der Draht zu der eigentlichen Audiosignalverarbeitung, die sich durch (Hall-/Echo-/Sustain-…) Effekt-Algorithmen und Heuristken manifestiert und dem eigentlich Werkzeug das Leben einhaucht, dass es benötigt um eine Audioverarbeitungsaufgabe mit mathematischen Modellen zu erfüllen.

Es ist mir als Informatiker bewusst, dass digitale Signale über eine Soundkarte gesendet werden, um dann über einen A/D-Wandler im analogen, physischen Raum Schalldruckschwankungen über Lautsprechermembranen zu erreichen. Ich kenne WAV-Dateien, und weiß dass diese in unterschiedlichen Sample-Raten (44100 Hz, 22050 Hz, 48000 Hz, 96000 Hz… [Samples/Sekunde])  und Auflösungen (z.B. 16 Bit, 24 Bit, 32 Bit float) existieren.

Als Cubase-Nutzer kenne ich die ASIO-Einstellungen (Menü Geräte –> Geräte konfigurieren) und habe bereits den Parameter Buffer Size bemerkt, welcher sich proportional auf die Eingangs- und Ausgangslatenzen, sowie reziprok auf meine CPU-Auslastung auswirkt.

asio_buffer_size

Als Musiker weiß ich geringe Latenzzeiten natürlich zu schätzen :-). Wer kann schon ein Instrument mit dem richtigen Timing auf den Takt einspielen, wenn er das akustische Ergebnis verzögert hört.

Nach dem Artikel Rechenlast beim Mixen verringern aus der c’t musik kreativ 2016 – S. 113 splittet man aufgrund dieses Buffers die Aufnahme in 3 Teile:

  1. Aufnahmephase: Alle komplexen INSERT-Effekte rausnehmen, kleine Sample Buffer einstellen, alle Spuren in Mono Aufnehmen die nicht zwingend Stereo sein müssen (Gesang, Kick, Bass….). Der Mix wird hierdurch auch transparenter, wenn man die Mono-Spuren im Nachgang im Stereopanorama verteilt.
  2. Mixingphase: Aufwendige Effekte hinzuschalten, Sample-Buffer erhöhen
  3. Masteringphase: Rohmix auf Stereospur mit 24-Bit Wortbreite rendern, hohen Sample-Buffer einstellen, so dass man die Masteringeffektkette wieder auf 96 khz fahren kann.

VST Insert-Effekte

Das Grundgerüst

Nachdem ich nun mit dem WDL-OL Framework von Oli Larkin und Visual Studio 2015 ein kompilierfähiges C++-Grundgerüst dank des Tutorials von Martin Finke erzeugt hatte, bemerkte ich schnell den Anwendungsbereich der Signalverarbeitung, der sich für mich anfänglich unkompliziert durch Probieren und Testen offenbaren sollte. Dabei machte ich ein paar (für den Profi triviale) Feststellungen, die ich hier niederschreiben möchte.

Wie sieht nun ein INSERT-Effekt in C++ aus? Was bekomme ich von der DAW von außen geliefert? Was kann ich damit machen? Wie gebe ich es an die DAW zurück?

basic1

In C++ passiert bei einem INSERT-Effekt alles in der Funktion „ProcessDoubleReplacing“, die als Übergabeparameter

  • die Amplitudenwerte des zu bearbeitenden Signals (*input)
  • die Amplitudenwerte des bearbeiteten Signals (*output)
  • die Puffergröße der ASIO-Einstellungen (hier 512)

als Zeiger erhält. Da diese Zeiger auf den tatsächlichen Wert im output-Buffer zeigen, kann die Funktion ohne Rückgabeparameter auskommen und wird VOID deklariert.

Digitale Verzerrung

Einer der einfachsten INSERT Effekte ist die digitale Verzerrung, bei der lediglich die Amplituden abgeschnitten werden müssen. Im Gegensatz zu einer weichen „analogen“ Verzerrung, wie sie durch die Röhren eine Gitarrenverstärkers statt finden kann und durch die Klangcharakteristik eines hart aufgehängten Lautsprechers in ihrer „Wärme“ abgerundet wird, legt die digitale Verzerrung lediglich durch das Abschneiden von Amplituden (auch Clipping genannt) wert auf Distortion / Verzerrung um jeden Preis.

Ein Gitarrenröhrenverstärker fügt dem Signal zunehmend geradzahlige Harmonische (Obertöne) zu und das Signal wird zunehmend weich begrenzt (soft clipping – Wärme).

Bei der digitalen Verzerrung nähern wir uns einer Rechteckform des Signals an (hard clipping – Digitale Verzerrung).

softvshardclipping

Links: Hard-Clipping (Digitale Verzerrung)
Rechts: Soft-Clipping (Wie bei einer Röhre)

Der Hard-Clipping-Algorithmus (links) flacht also nicht wie rechts die Spitzen ab sondern nimmt einfach den überschreitenden Wert als gegebenes Maximum hin. Programmiert sieht das folgendermaßen aus:

mainfunction

mThreshold: Beinhaltet einen Wert zwischen 0 und 1, der mit einem Regler eingestellt wurde.

fmin(): Gibt hier den input-Amplitudenwert zurück, es sei denn mThreshold wird überschritten – dann wird mThreshold zurückgegeben.

fmax(): Gibt den input-Amplitudenwert zurück, es sei den mThreshold wird unterschritten, dann wird -mThreshold zurückgegeben.

 

Oszillation auf die Welle „draufmodulieren“

Ich schrieb eine Klasse „Oscillator.cpp“, die eine Sinus- bzw. Cosinusschwingung generierte. Zunächst dachte ich, dass das simple „addieren“ einer Welle auf die andere eine völlig andere Klangcharakteristik erzeugen würde…. aber es erzeugte eher etwas wie das „Zusammenmischen“ von zwei Signalquellen, so als ob man ein Signal mit dem Mischpult in das andere „reindreht“. Wenn ich so recht drüber nachdenke kann ein Lautsprecher ja auch nur „eine“ Welle erzeugen… diese Welle muss sich aber je Signalquelle unterscheiden… Man erreicht also das „Mixen“ mehrerer Signalquellen durch das aufaddieren von Schwingungen. Und an dieser Stelle wird einem auch klar, dass eine natürliche Schwingung, beispielsweise der Ton eines Instrumentes, aus mehreren Teilschwingungen besteht und nur durch unsere Erfahrung als zwei oder mehrere unterschiedliche Signalquellen interpretiert werden kann. So hat zum Beispiel bei einem Schlagzeug die Bass-Drum einen hohen „Klick-Anteil“, einen druckbringenden „Körper-Anteil“ und einen tiefen „Bass-Anteil“, den man über einen Equalizer separieren kann, und der sich alleinstehend völlig anders anhört.

basic3

Phasenauslöschung: Wenn sich Wellen gegenseitig auslöschen

Ich richtete den linken und den rechten Kanal nun aufeinander und dachte dass sich das „zugemischte“ Signal durch die 180 Grad Phasenverschiebung (um PI) vollständig auslöschen müsste. In Wirklichkeit wurde es aber nur leiser. Ich vermutete, dass hier die kreisförmige Ausdehnung des Schalls aus den Boxen eine Rolle spielt. Wenn man dies bereits im Rechner macht, ist das Resultat bekanntermaßen Stille.

sin(x)+sin(x+PI)=0;

Der Cosinus ist quasi eine Phasenverschiebung um 90 Grad. In einer DAW könnte dies durch das Verschieben einer Audiospur nach rechts bedeuten.

phase_02

180 Grad ist dann noch weiter geschoben…

phase_03

(Bild-Quelle: delamar.de)

Jetzt werden beim Zusammenmischen der beiden Quellen die Amplitudenwerte addiert, wie es im Abschnitt „Oszillation auf die Welle draufmodulieren“ bereits gezeigt wurde. Und genau diese Tatsache führt also zu einer Phasenauslöschung! Eine Phasenauslöschung kann also auch durch die ungünstige Lage von Audiomaterial auf der Zeitachse stattfinden. Wen man das Material ein Stück nach rechts oder links schiebt (natürlich so, dass es nicht merkbar ist) könnte das Resultat auch wieder anders aussehen.

Wenn ich nun die Boxen aufeinander richte erhalte ich tatsächlich Stellungen im Raum, an denen das Signal fast verschwunden ist. Durch die kreisförmige Ausdehnung des Schalls um die Boxen wird es aber nicht vollständig terminiert.

Hier habe ich mein Experiment dokumentiert:

Schalte ich den Cubase Stereo Out Mix auf Mono, indem ich das „Stereo Enhancer“ Plugin in den INSERT-Effekten des Stereo-Outs auf Mono hinzuschalte (links unten ist ein MONO-Button wenn es geladen wurde), ist das Signal wirklich verschwunden bevor es den Computer verlassen hat (Phasenauslöschung bereits Digital).

VST Instrumente

Der Unterschied zu Insert-Effekten

Im Tutorial von Martin Finke wird ein Python-Skript verwendet, um aus den IPlugSamples ein Template für ein neues Projekt zu generieren. Als Grundlage meiner bisherigen Projekte wurde immer das selbe Startprojekt IPlugEffekt verwendet. Meine Vermutung war zunächst, dass jetzt ein anderes Template als Grundlage für ein VST Instrument genutzt wird. Allerdings kann man einen VST Insert Effect mit wenigen Handgriffen in der Quelldatei „ressource.h“ in ein VST Instrument umwandeln.


// #define PLUG_CHANNEL_IO "1-1 2-2"
#if (defined(AAX_API) || defined(RTAS_API))
#define PLUG_CHANNEL_IO "1-1 2-2"
#else
// no audio input. mono or stereo output
#define PLUG_CHANNEL_IO "0-1 0-2"
#endif

// ...
#define PLUG_IS_INST 1

// ...
#define EFFECT_TYPE_VST3 "Instrument|Synth"

// ...
#define PLUG_DOES_MIDI
[/javascript]

"0-1 0-2" bedeutet kein Input und einen Output (Mono) oder  kein Input und zwei Outputs.

"PLUG_IS_INST 1" macht aus dem INSERT Effect endgültig ein Instrument.

Inputs sind bei Instrumenten unnötig, da ein Instrument selber als Signalquelle für den Gesamt-Mix genutzt wird. Die Funktion "ProcessDoubleReplacing" bekommt als Übergabeparameter allerdings weiter hin die Inputs geliefert. Ich habe noch nicht herausgefunden wofür das gut sein soll ;-).

Kostenloses VST3 Effect-Plugin / Free VST3 effects plugin: Digitale Verzerrung / Digital Distortion

Download kostenloses VST3 Plugin Digitale Verzerrung | VST3 Effect Download

Nach dem Download können Sie das Plugin einfach in Ihr VST3 Verzeichnis kopieren (z.B. C:\Program Files (x86)\Common Files\VST3)

Just copy the VST3 Plugin into your VST3 Directory (i.e. C:\Program Files (x86)\Common Files\VST3 ).

Bei diesem VST3 Plugin handelt es sich um eine einfache digitale Verzerrung.

Der Regler lässt sich von 0 Prozent bis 100 Prozent (links) drehen, je näher man an die 100 Prozent kommt, desto stärker werden die Amplituden abgeschnitten. Bei leiseren Signalen muss man ganz nach links drehen. Am 100 % Anschlag ist allerdings die Welle ausgelöscht :-). Also immer ein paar Cent weiter rechts bleiben und die Lautstärke wieder anheben (diese wird ebenfalls abgeschwächt). Eine automatische Lautstärkenkorrektur findet nicht statt, da die Lautheit durch die Annäherung an ein Rechtecksignal relativ hoch wird, sollte dies nämlich besser individuell eingepegelt werden.

Screenshot: Der Effekt „Distortion -> Hard Digital Distortion“ wurde bei den INSERT-Effekten einer Spur in Steinberg Cubase an erster Stelle ausgewählt und dessen GUI über den „e“-Button hervorgebracht.

digitale_verzerrung