Programm läuft unter Linux, aber stürzt ab unter Windows
-
Hallo!
Ich schreibe an einem Programm zur Analyse von grundlegenden Strukturen von Musikstücken (z.B. Metrik, Harmonik). Den Teil für die metrische Analyse habe ich fertig, und unter Linux läuft das Programm auch einwandfrei. Nun möchte ich aber, dass es auch unter Windows läuft. Hier stürzt das Programm aber ab. Ich habe es mit zwei Compilern unter Windows 98 versucht (MinGW und VC6), und das Resultat war in beiden Fällen ein Absturz.
Beim VC6 konnte ich feststellen, in welcher Funktion der Fehler auftrat (dank exception). Beim MinGW wurde aber noch nicht mal die exception geworfen, bzw. ausgegeben.
Die fehlerhafte Funktion:void MeasureVec::createMeasures(pipVec* pips, int base) { pPips=pips; baseLevel=base; // Anzahl measures bestimmen int beatCount=countBeats(); int firstBeat=findFirstBeat(); int lastBeat=findLastBeat(); if(firstBeat==0) --beatCount; if(lastBeat==pPips->size()-1) --beatCount; // Grösse des measure-Vektors anpassen, und ggf. zuerst löschen. measures.clear(); cerr << "Entry " << beatCount << " " << measures.size() << endl; try { measures.resize(beatCount+1); // <-- Hier geht ahnscheinend was schief... } catch(exception& e) { cerr << e.what() << endl; exit(1); } catch( ... ) { cerr << "Ein unbekannter Fehler ist aufgetreten!" << endl; exit(1); // <-- VC6 gibt diese Meldung aus und beendet das Programm } cerr << "resized" << endl; // Mittlere Anzahl pips zwischen zwei Schlägen der Basisebene berechnen double average_pips_per_beat=static_cast<double>((lastBeat-firstBeat)/beatCount)+0.5; int pos=0; // Falls der erste Schlag der Basisebene nicht auf pip[0] fällt, einen Dummy-pip einfügen und die Teilungen für diesen // ersten measure berechnen. Das Intervall zwischen dem Dummy-Pip und dem ersten "echten" Schlag beträgt // average_pips_per_beat pips. Anschliessend wird der Inter-Measure-Score berechnet. if (firstBeat>0) { measures[pos].left=firstBeat-static_cast<int>(average_pips_per_beat); measures[pos].right=firstBeat; computeBinaryDivision(pos); computeTernaryDivision(pos); computeInterMeasureScores(pos); ++pos; } // Für jeden measure die beste binäre bzw. ternäre Teilung berechnen. Anschliessend den Inter-Measure-Score berechnen measures[pos].left=firstBeat; for(int i=firstBeat+1; i< pPips->size(); ++i) { if((*pPips)[i].isBeat>=baseLevel) measures[pos].right=i; else continue; computeBinaryDivision(pos); computeTernaryDivision(pos); computeInterMeasureScores(pos); ++pos; measures[pos].left=measures[pos-1].right; } // Falls der letzte Schlag der Basisebene nicht auf den letzten pip fällt, wieder einen Dummy-pip einfügen, diesmal // am Schluss. Anschliessend Inter-Measure-Score berechnen. if(lastBeat<pPips->size()-1) { measures[pos].right=lastBeat+static_cast<int>(average_pips_per_beat); computeBinaryDivision(pos); computeTernaryDivision(pos); computeInterMeasureScores(pos); } }Das Problem liegt offenbar im Vector measures. Der sieht folgendermassen aus:
std::vector<measure> measures;measure ist ein Struct mit diesem Aufbau:
struct measure { int left; int right; int binary; int ternaryOne; int ternaryTwo; double binaryScore; double ternaryScore; double bestScoreBinary; double bestScoreTernary; int bestBinaryScore_raised_by; int bestTernaryScore_raised_by; };Der Aufruf der kritischen Funktion erfolgt folgendermassen:
void Meter::computeLowerLevels(int baseLevel) { MeasureVec temp(pm); // Alle Ebenen unter dem Tactus berechnen (kleinste Ebene ist per Definition 0) while(baseLevel>0) { temp.createMeasures(&pips, baseLevel); // Measures für die neue Ebene füllen, interne Scores und // Inter-Measure-Scores berechnen measures.push_back(temp); // Measure speichern. labelLowerBeats(baseLevel); // Schläge der Ebene baseLevel-1 markieren --baseLevel; // nächsten Level bestimmen } }Der erste Aufruf von createMeasures() klappt, aber beim zweiten Aufruf stürzt das Programm unter Windows ab...
Hat jemand eine Idee, was da schief läuft?
-
Welche Fehlermeldung gibt der Compiler aus?
-
Das Programm compiliert ohne Fehlermeldungen des Compilers. Erst wenn ich es laufen lasse, stürzt es ab, und zwar wie gesagt nur unter Windows. Beim MinGW erhalte ich dann eine Fehlermeldung des Betriebssystems (ungültige Seite in Kernel32.dll), und beim VC6 wird eine Exception ausgeworfen.
Unter Linux funktioniert alles tadellos. Ich hatte mal den Verdacht, es läge am Compiler, aber wenn bei zwei verschiedenen Compilern dasselbe Resultat rauskommt, liegts wohl nicht daran.
-
Debuggen.
-
Lass es mal unter Linux mit valgrind laufen.
-
Dein Programm interessiert mich
Hanns
-
@Ponto: Vielen Dank für die Hilfe! Der Tipp mit Valgrind hat voll eingeschlagen! In der for-Schleife von createMeasures() konnte u.U. über die Bereichsgrenzen des vector hinaus geschrieben werden - mit den entsprechenden Konsquenzen. Das ist jetzt behoben, und das Programm läuft jetzt mit Linux und Windows ohne Probleme.
@HannsW: Also mein Programm (bzw. der Teil, den ich bis jetzt fertig habe) beruht auf einem Algorithmus, der von David Temperley entwickelt wurde. Temperley hat ein Buch über Computergestütze Musikanalyse geschrieben (The Cognition of Basic Musical Structures, 2001: http://www.amazon.de/exec/obidos/ASIN/0262701057/qid=1121979808/sr=1-1/ref=sr_1_8_1/302-9583128-6418464), in denen er verschiedene Algorithmen zur Analyse von tonaler Musik vorstellt. Er hat diese Algorithmen auch selber implementiert, und die Quellcodes stehen zum Download bereit:http://www.link.cs.cmu.edu/music-analysis/
Die Algorithmen leiten sich aus sogenannten Präferenzregeln ab, das sind quasi "weiche" Regeln, die nicht nur mit "ja" oder "nein" beantwortet werden können, wie die klassischen "wenn-dann"-Regeln. Ein Beispiel für eine solche Regel wäre (für die Analyse der metrischen Struktur eines Musikstücks): "Bevorzuge betonte Schläge an Punkten, an denen möglichst viele neue Töne angeschlagen werden." Mehrere solcher Regeln ergeben dann ein komplexes System, in dem die einzelnen Regeln untereinander wechselwirken, sich gegenseitig verstärken oder abschwächen. So kann man dann schliesslich relativ genau die Punkte im Stück bestimmen, auf denen z.B. (Takt-)Schläge zu liegen kommen.
Was ich jetzt mache ist einerseits die Algorithmen in c++ re-implementieren und gleichzeitig einige selbst erdachte Erweiterungen einbauen, die die Leistungen verbessern sollen. Bei der Metrik-Komponente deuten die ersten Resultate auch darauf hin, dass mir das tatsächlich gelingen könnte (aber ich habe noch keine wirklich systematischen Tests gemacht, das ist einfach der erste Eindruck).