Wahl der "richtigen" Programmiersprache für ein Audio-Projekt
-
Hallo,
in den letzten Jahren habe ich (Hobbymäßig) an einigen Realtime-Routinen zur Audio-Synthese gearbeitet.
Diese habe ich in (Mikrontroller-) C32 und Assembler entwickelt. Lookup-Tabellen usw. habe in C# auf dem PC vorberechnet.
Da ich aber mittlerweile ziemlich an die Grenzen der Embedded-Hardware stoße habe ich mich entschieden das ganze nun doch als reine PC-Software zu realisieren, da brauche ich mich mit knappen Lookup-Speicher-Ressourcen, Fixed-Point Arithmetik und mangelndem Oversampling nicht weiter herumzuquälen
Aber nun stehe ich einfach vor der Wahl der "richtigen" Programmiersprache für dieses Projekt. Beruflich entwickel ich in C# und VB.NET und hab darin dementsprechend die besten Kenntnisse. Aber eben auch "Bammel", dass C# vielleicht aus Performance-Sicht nicht die Beste Wahl ist.
Die Embedded C- und Assemblercodes kann ich nicht so ohne weiteres auf die Windows-Welt portieren, da ich hierbei auch viel mit der Hardware getrickst habe (z.B. IRQs und Timer, etc.). Und in C++ fehlen mir völlig die Kenntnisse.
Macht es in so einem Fall Sinn, dass ich mich erstmal in C++ einarbeite? Da ich schon so lange daran arbeite muss es ja nicht unbedingt ne RAD-Lösung sein, wenns denn sein muss werde ich wohl C++ lernen müssen.
Oder ließe sich so eine Echtzeit-Anwendung heutzutage durchaus auch mit C# realisieren? Mir fehlen da nämlich leider jegliche Vergleichswerte und alle Threads die ich bislang im Internet dazu gefunden habe enthalten nicht wirklich nützliche Infos für mich, sondern oftmals leider nur rumgeflame beider Lager.
Bei den halbwegs brauchbaren Vergleichen sehe ich einerseits Charts wo bei einigen Tests C++ besser abschneidet, bei anderen widerum schlechter als C#.
Meine Algorithmen arbeiten viel mit SINC-Funktionen und Fixed-Point Multiplikationen (hier würde ich auf dem PC natürlich super gerne auf Fließkommaarithmetik umsteigen!).
Nebenbei habe ich mir auch Delphi, Java und Basic-Dialekte angeschaut. Bei Delphi habe ich aber sicherlich ebensoviel Einarbeitungszeit wie bei C++ und bei den Basic-Compilern konnte ich zwar feststellen das diese im Gegensatz zu früher ziemlich gut geworden sind, aber schon deutlich langsamer als C#/VB.NET (zumindest bei meinen rudimentären Tests). Bei Java habe ich bei meinen Tests festgestellt das die GUI extrem langsam ist (das mag aber nicht unbedingt an Java selber liegen, sondern evtl. an meiner Unwissenheit, aber dies ist mir auch bei anderen Java-Anwendungen schon mal aufgefallen).
Am liebsten wäre mir daher mal eine Einschätzung von Leuten die Erfahrung in beiden Welten haben (.NET und Native C++).
PS: es geht mir wirklich nicht darum welche Sprache nun allgemein "besser" ist, sondern nur für so einen Anwendungsfall wie ich ihn beschrieben habe.
Vielen Dank für alle Tipps im voraus und viele Grüße
MatzeTante Edit(h) sagt: 3 Typos korrigiert.
-
gelöscht, weil obsolet.
-
Meiner Ansicht nach liegt die Zukunft, was Softwarentwicklung anbelangt, bei
C++ und/oder Java.C++ ist meiner Auffassung nach unterm Strich besser als Java, z.B. in Bezug auf die Geschwindigkeit, aber da streiten sich die Experten. Auch braucht man natürlich keine Engine, damit die Programme laufen.
Eventuell mag es Programmiersprachen geben, die für spezielle Softwareprodukte
besser geeignet sind, als die beiden, der Unterschied dürfte aber minimal sein.C# ist extrem abhängig von .Net, das alleine würde mir schon reichen, um C++
vorzuziehen.Wenn Du schreibst, daß du Assembler gelernt hast, brauchst Du keine Angst davor zu haben, C++ zu lernen. Die Sprache ist im Vergleich zu Assembler sehr leicht zu lernen.
-
Aber die GUI bei JAVA ist doch einfach Hardcore???
-
Java würde ich mal außen vor lassen. Wenn du nur für Windows schreiben willst nimm C#, das sollte locker reichen, wenn du jetzt erst an die Grenzen von Embedded-Hardware stößt. (Die Sprache die man am besten kann bietet sich immer an, solange sie in etwa das erfüllt, was man haben möchte.)
Wenn du aber plattformunabhängig programmieren willst nimm lieber C++.
-
Meiner Ansicht nach liegt die Zukunft, was Softwarentwicklung anbelangt, bei C++ und/oder Java.
Ich bete dafür, dass dem nicht so ist.
Versteh mich nicht falsch, C++ ist keine so schlechte Sprache und für den hier gefragten Anwendungszweck wahrscheinlich wirklich relativ gut geeignet, aber die Zukunft der Softwareentwicklung? Nein, die liegt woanders. Wo, weiß ich zwar nicht, aber nicht bei C++.C++ ist meiner Auffassung nach unterm Strich besser als Java, z.B. in Bezug auf die Geschwindigkeit, aber da streiten sich die Experten.
Keinst ernstzunehmender Experte behauptet, dass Java schneller sei als C++.
Wenn Du schreibst, daß du Assembler gelernt hast, brauchst Du keine Angst davor zu haben, C++ zu lernen. Die Sprache ist im Vergleich zu Assembler sehr leicht zu lernen.
Qutasch. Assembler ist deutlich simpler als C++. C++ gehört mit zu den kompliziertesten Sprachen überhaupt.
Warum nicht einfach bei C bleiben? Für's Portieren musst du halt die Tricksereien etwas umschreiben, aber ein kompletter Neuanfang lohnt sich selten.
-
Also der Tipp mit C ist natürlich von Dir auch gut. Aber womit kann ich denn (heute) noch auf C kompilieren?
-
GoaZwerg schrieb:
Also der Tipp mit C ist natürlich von Dir auch gut. Aber womit kann ich denn (heute) noch auf C kompilieren?
oO Ich dachte du fragst weil du von C weg willst. Und was ist das für eine Frage? Mit einem C Compiler? Visual Studio, GCC, ..
-
Nee, ich will net unbedingt davon weg. Ich programmiere nur auf den MC damit.
-
Ähem? schrieb:
Keinst ernstzunehmender Experte behauptet, dass Java schneller sei als C++.
Das habe ich auch nicht behauptet, aber Du kannst das Thema gerne mal
im nächsten Java-Forum postenÄhem? schrieb:
Qutasch. Assembler ist deutlich simpler als C++. C++ gehört mit zu den kompliziertesten Sprachen überhaupt.
Wirklich? Dann schreib doch mal mit Assembler, sagen wir, einen std::vector, wie es ihn bei C++ gibt. Oder z.B. eine Klasse.
Ich behaupte, daß das mit C++ wesentlich leichter zu lernen ist als mit Assembler.Mag sein, daß der Grundwortschatz von Assembler wesentlich geringer ist als der von C++, bloß was nützt das, wenn die Komplexität binnen kürzester Zeit so dermaßen ansteigt, daß nur noch absolute Profis den Überblick behalten.
-
ich glaube ihr redet leicht aneinander vorbei.
assembler: einfach, aber es ist schwieriger damit etwas komplexes zu realisieren
c++: komplex, dafuer sind komplexe dinge einfacher damit zu realisierenist oft so, einfache tools beduerfen mehr schweissarbeit.
@GoaZwerg
solange das nur fuer dich ist und du eine halbwegs moderne cpu + genug ram hast, benutzt einfach das womit du am besten zurecht kommst. selbst wenn c# in manchen dingen 10mal langsammer ist, kannst du mit c++ auf einem normalen pc mit 100fps ein H264 video encoden, das sind datenmengen bzw. berechnungen bei denen du vermutlich nur noch rauschen hoeren wuerdest, wenn dein sound mixer/generator sie verarbeiten/generieren wuerde. es gibt schon auf dem ipad rebirth http://www.youtube.com/watch?v=zomsMea6KxMalso achte nur auf deine produktivitaet/vorlieben.
-
GoaZwerg schrieb:
Aber nun stehe ich einfach vor der Wahl der "richtigen" Programmiersprache für dieses Projekt.
faust (=functional audio stream)
-
faust (=functional audio stream)
Das kannte ich noch nicht, sieht auf den ersten Blick ziemlich interessant aus! Danke für den Tipp.
-
Ist doch irgendwie gar nicht schwer, c mit demm gcc auf Linux. Und Linux asm und Hardwarezugriffe sind auch nicht so übel im Gegensatz zu Windows. Und Charli Petzolds wichtige Windowsbücher bauten auf C auf. Eins nach dem anderen, würde ich sagen, c und java ausreizen können, dann C++. Das ist aber ein bißchen doof, weil java eine eigene Api hat. Aber mit c und asm und den richtigen Bibliotheken kommt man auch gut über die ersten Runden. Windows-Assembler ist ein eigenes Thema, man braucht eigentlich erstmal gute Winapi Grundlagen. Ich finde C drängt sich da irgendwie total auf.
-
Heute Abend hab ich mal Zeit gefunden ein paar weitere Tests zu machen.
Jetzt bin ich doch etwas verwirrt
Ich habe einfach mal stumpf getestet wieviele Int32-Inkrements ich in ca. 1000ms hinbekomme, auf einem PIC32MX Controller getaktet mit 80 MHz, einem Parallax-Propeller mit 8 COGs, sowie auf meinem Laptop (2,4 GHz, Duo-Core mit Hibernate für 4 virtuelle Kerne, aber getestet hab ich natürlich nur 1 Core) in C++ Native VS2010, C++ Native MinGW, C++ CLR, C# und VB.NET. Daneben hab ich noch nen DSPIC auf 16 Bit getestet, der kommt bei höchster empfohlener PLL-Konfiguration auf 40 MIPS @ 16 Bit (wegen der 16 Bit fällt der aber aus dem Vergleich raus).
Getestet habe ich hierbei nur erstmal Fixed-Point.
Auf dem PIC32 erreiche ich, in Assembler, wie erwartet zuverlässig die 80 MIPS (ohne Loops, bzw. mit Hardware-Loops, darum hinkt der Vergleich mit dem PC sowieso etwas, die Werte vom 32MX sind also eher theoretischer Natur), die Werte auf dem Parallax konnte ich nicht vernünftig messen, aber da er eh keinen Hardware-Multiplizierer bzw. keine FPU und keinen DSP hat und viel zuwenig Speicher ist der eh sowieso schwer zu vergleichen.
Mit der Stopwatch und optimiertem Release-Built und mit Schleife erreiche ich in C#, CLR C++ und VB.NET nur 13 MIPS (komischerweise war VB.NET in mehreren Fällen ein klein wenig schneller als Unsafe-C# und CLR C++), im Debug-Mode in allen Fällen sogar nur 6 MIPS (!) im Mittel.
Dann habe ich den C# und VB.NET-Code so umgestellt das er mit Threading Schleifenlos arbeitet, da komme ich auf ca. 106 MIPS. Aber auf meiner ursprünglichen Platine werkeln 3 Stück von den PIC32 in Serie, was somit 4,5 DMIPS ergibt (effektiv, zumindest nach meinen Versuchen, 240 MIPS @ 32 Bit).
Der VS2010 C++ kommt, mit Schleife, aber ohne Threading, auf ca. 56 MIPS und der GCC lag im Mittel stets 10 MIPS darunter. Mangels Erfahrung in der Programmiersprache C++ konnte ich es dort nicht mit Threading probieren.
Natürlich is so ein Benchmark nicht wirklich zu legitim, aber ich wollte ja auch nur mal einen groben Vergleich haben.
Was mich jetzt daran irritiert: der PIC32 hat 1.5DMIPS, ein Laptop hat doch zig-mal mehr und zudem ne FPU?!
Klar, C# mit Unsafe-Code und Optimierung kommt auf über 100 MIPS, aber das ist doch nicht wirklich viel mehr als so nen Popel-32MX?
Eigentlich hätte ich nen Faktor von 1000 oder mehr für C# erwartet?!
*Verwirrt bin*
-
Das erinnert mich hieran:
http://www.bernd-leitenberger.de/benchmark.shtmlUnd Intel hat natürlich ein gutes Marketing
Und auf dem Rechner hat man auch noch ganz andere Dinge nebenbei mitlaufen.
-
Nur mal so aus Interesse.. wie hast du denn die Integerincrements gemessen, ohne dass das komplett wegoptimiert wurde?
-
Muss mich erstmal korrigieren, hatte was von Schleifenlos geschrieben, diese Formulierung war Murks.
@cooky: wenn man das Ergebnis ausgibt wird es nicht wegoptimiert. Verwendet man die Variable allerdings hinterher nicht mehr dann scheint der IL-Compiler das zu merken und optimiert es dann einfach weg, meines Wissens nach.
-
Könntest du mal deinen Testcode für C++ und C# posten?
-
Ich habe jetzt mal ein etwas erweitertes Testprogramm geschrieben, dass dürfte dann ausagekräftiger sein. Hier die C# Version:
using System; using System.Diagnostics; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { const int sampleRate = 44100; const double leaky = 0.99; double position = 0; double delta = 1; double max = 0; double posSinc = 0; double dcOffset = 0; double @out = 0; Stopwatch sw = new Stopwatch(); // Impulse-Train Sweep Test sw.Start(); for (int frequency = 50; frequency <= Convert.ToInt32(sampleRate * 0.5); frequency++) { max = 0.5 * sampleRate / frequency; dcOffset = -0.49 / max; position += delta; if (position < 0) { position = -position; delta = -delta; } else if ((position > max)) { position = max + max - position; delta = -delta; } posSinc = Math.PI * position; if (posSinc < 1E-05) { posSinc = 1E-05; } @out = leaky * @out + dcOffset + Math.Sin(posSinc) / posSinc; } sw.Stop(); Console.WriteLine(string.Format("Dummy-Out: {0}", @out)); Console.WriteLine(string.Format("{0}µs", sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)))); Console.ReadKey(); } } }
-
Und hier dasselbe (hoffentlich) in C++ zusammengefrickelt (VS 2010):
#include "stdafx.h" #include <math.h> #include <iostream> using namespace std; #include "windows.h" int _tmain(int argc, _TCHAR* argv[]) { const int sampleRate = 44100; const double leaky = 0.99; double position = 0; double delta = 1; double max = 0; double posSinc = 0; double dcOffset = 0; double out = 0; // Impulse-Train Sweep Test LONGLONG g_Frequency, g_FirstNullCount, g_LastNullCount, g_FirstCount, g_LastCount; if (!QueryPerformanceFrequency((LARGE_INTEGER*)&g_Frequency)) printf("Performance Counter nicht vorhanden"); double resolution = 1000000 / ((double)g_Frequency); printf("Frequenz des Counters: %lld kHz\n", g_Frequency/1000); //lld -> LONGLONG darstellung printf("Dadurch maximale Aufloesung: %4.5f us\n", resolution); //null-messung QueryPerformanceCounter((LARGE_INTEGER*)&g_FirstNullCount); QueryPerformanceCounter((LARGE_INTEGER*)&g_LastNullCount); double nulltime = (((double)(g_LastNullCount-g_FirstNullCount))/((double)g_Frequency)); printf("Null-Zeit: %4.5f us\n", nulltime * 1000000); //beginn messung QueryPerformanceCounter((LARGE_INTEGER*)&g_FirstCount); for (int frequency = 50; frequency <= sampleRate * 0.5; frequency++) { max = 0.5 * sampleRate / frequency; dcOffset = -0.49 / max; position += delta; if (position < 0) { position = -position; delta = -delta; } else if ((position > max)) { position = max + max - position; delta = -delta; } posSinc = 3.14159265358979323846 * position; if (posSinc < 1E-05) { posSinc = 1E-05; } out = leaky * out + dcOffset + sin(posSinc) / posSinc; } //2. Messung QueryPerformanceCounter((LARGE_INTEGER*)&g_LastCount); double dTimeDiff = (((double)(g_LastCount-g_FirstCount))/((double)g_Frequency)); //Von der gemessenen Zeit die "Null-Zeit" abziehen, um genauer zu werden double time = (dTimeDiff - nulltime) * 1000000; //mikro-sekunden printf("Zeit: %4.5fus\n" ,time); printf("Dummy-Out: %4.5f\n", out); int get; cin >> get; return 0; }