einfaches metronom
-
Du willst doch, laut Threadtitel, ein "einfaches metronom" programmieren.
Also tu das auch, ohne groß über Multithreading etc. zu grübeln.
Mit Beep, Sleep und GetAsyncKeyState hast du schon mal eine gute Grundlage, mit der du auf den ersten Blick weit kommenkönntest.
-
#include "stdafx.h" #include <iostream> #include <ctime> #include "windows.h" #include <stdio.h> #include <stdlib.h> using namespace std; class metronom{ private: LARGE_INTEGER frequency; LARGE_INTEGER t1, t2; double elapsedTime; double correction; public: metronom(); void tick(double); void estimatecorrection(void); }; int _tmain(int argc, _TCHAR* argv[]) { metronom m; m.estimatecorrection(); m.tick(120); Sleep(5000); return 0; } void metronom::tick(double bpm){ while(true){ QueryPerformanceCounter(&t1); QueryPerformanceFrequency(&frequency); while(true){ QueryPerformanceCounter(&t2); elapsedTime = (t2.QuadPart - t1.QuadPart)*1000 / frequency.QuadPart; if(elapsedTime/1000>=(60/bpm-correction/1000)){cout<<"tick"<<"\n";break;} } } }; metronom::metronom(){correction=0;}; void metronom::estimatecorrection(){ bool compare; double meassure[10]; double mean=0; for(int i=0; i<10;i++){ QueryPerformanceCounter(&t1); compare=(elapsedTime/1000>=(60/70-0,9)); //vergleichbare operationen cout<<"tick"<<"\n"; //vergleichbarer dreck QueryPerformanceCounter(&t2); QueryPerformanceFrequency(&frequency); meassure[i] = (t2.QuadPart - t1.QuadPart)*1000 / frequency.QuadPart; mean+=meassure[i]; } correction=mean/10; };naja,das hier wäre schonmal ein Ansatz, jetzt fehlt nur noch der tatsächliche Sound.
Aber zu frieden bin ich damit wiegesagt nicht.
Aber Entschuldigung, jetzt weiß ich erst was ihr mit Timern und Interrupts meint. Ich dachte da erst an was anderes. Aber wie ist das dann genau mit der Tonabspielung und der Takteingabe? Das Programm kann doch nicht einfach während der User etwas eintippt, aufeinmal ne andere Routine ansteuern? da fühlt man sich doch verarscht?
Bzw was passiert wenn grade mitten im Abspielen eines Ton der Timer das Interrupt auslöst?EDIT:
Wichtig sind auch die Prioritäten, also wie lange das Programm in welcher Subroutine verweilt. Da muss man die Timer justieren.
Kann man das so machen, dass beim Eintippen ein Hadrwareinterrupt ausgelöst wird, der die Timer so einstellt, dass kurzfristig die Verweilsdauer in der Taktabfragenroutine eine größere Priorität bekommt, und in der restlichen Zeit die Tickroutine die große Priorität hat?
-
Wie gefällt dir meine folgende Umsetzung?
#include <windows.h> int main() { int freq = 262, dur = 100, pause = 1000; while(!GetAsyncKeyState(VK_RETURN)) { if(GetAsyncKeyState(VK_INSERT)) pause += 100; else if(GetAsyncKeyState(VK_DELETE) && pause>100) pause -= 100; Beep(freq, dur); Sleep(pause); } return 0; }
-
auch nicht schlecht, aber eine diskrete Eingabe eines Starttaktes ist mir trotzdem wichtig. Danach könnte man das scrittweise increase und decrease verwenden um resourcen zu sparen.
-
Nun gut, den User die Dauer von
pausebestimmen zu lassen ist hoffentlich kein Problem
-
der Starttakt kann von Musikpassage zu Musikpassage varrieren, zusätzlich kommt noch der Skill des Users am Instrument. Je besser, oder je fauler, umso weniger wird bei kleineren Takten geübt.
EDIT: außerdem hab ich grade deinen Code mit einem Online metronom verglichen: Beim Defaulttempo, also pause=1000 --> 60 bpm hat der code einen starken versatz.
Da hält mein code länger durch, allerdings weil da eine korrekturfunktion drin ist.
-
Kann man diese Interrupttimer am PC umsetzen?
wie schafft man es z.B., eine abgebrochene Routine nacher an der selben Stelle fortzuführen? und wie löst man die oben genannten probleme?
-
Habe ja nicht behauptet, dass mein Code besser wäre als deiner

Wollte nur mal deine Meinung dazu wissen, ob das irgendwie deinen Vorstellungen entspricht.
Und das mit dem Versatz habe ich beim kurzen Test nicht bemerkt.Einen Interrupttimer umsetzen "kann" man sicher, ist aber imo ziemlich kompliziert.
Und wie gesagt, unter "einfaches metronom" wäre dies dann sicherlich nicht mehr einzuordnen.
-
ich weiß, "einfach" war da eher trotzig gemeint, etwa wie: "ich will doch EINFACH nur ein metronom, dass wenigstens userfreundlich ist!"
-
ist es möglich assembler und c++ zu hybridisieren? und dann den interrupthandler per assembler zu machen? oder kann interrupthandler nur in einer puren sprache umsetzen? könnt ihr mir dazu referenzen geben?
ich hab jetzt schonmal eine seite gefunden die ich am durchlesen bin:
http://www.drdobbs.com/implementing-interrupt-service-routines/184401485?pgno=1
-
Ohje, da geht so viel durcheinander. Erstmal: Prozessoren sind schnell. Sehr schnell. Du kannst dein Metronom abspielen, auf Eingaben reagieren und nebenbei Pi auf ein paar Millionen Stellen berechnen, gar kein Problem.
Die Soundausgabe wird nicht vom Prozessor gemacht, sondern der Prozessor tut wave-Daten in ein Stück Speicher und sagt der Soundkarte "mach mal". Daher spielt der Sound weiter, obwohl der Prozessor was anderes tut. Auf einem Mikrokontroller wäre es ein DMA-Controller oder PDCA oder wie die sonst heißen. Das sind extra Chips die das Datenfüttern übernehmen, damit die CPU sinnvolle Dinge tun kann.Ein Interrupthandler ist eine einfache Funktion. Der Prozessor springt beim setzen eines Pins an eine Stelle im Speicher, das nennt sich dann Interrupt. Der Code an der Stelle im Speicher ist der Interrupthandler. Den kannst du in Assembler, C, C++, JavaScript oder sonstwas schreiben (was sind pure Sprachen?). Zum "Hybridisieren" sei inline assembly erwähnt. Unter Windows hast du aber soweit ich weiß keinen Zugriff auf diesen lowlevel Kram. Dafür gibt es Timer, die dasselbe in komfortabel tun. Bei einem Mikroprozessor steht in der Doku wie man dem Prozessor sagt bei welchem Pin er wo hin springen soll. Dann verbindet man noch den Interruptpin mit der Uhr oder dem Taktzähler und schon läuft der Interrupthandler alle x Millisekunden.
Ich würde dir raten zuerst dein Problem zu definieren. Was soll wann passieren, wie sieht die Ein- und Ausgabe aus? Welcher Prozessor soll es sein?
Btw du kannst auch einfach die Zeit speichern:start = getTime(); while (true){ playTick(); //wird trotz Störungen alle delay Zeiteinheiten ausgeführt sleep(getTime() - start + delay); start += delay; }Was du hier sehen sollst, ist, dass playTick() keine Zeit verliert, sondern alle "delay" Zeiteinheiten tickt. Sollte der Prozessor beschäftigt sein tickt er später, das lässt sich nicht vermeiden, aber der nächste Tick stimmt wieder.
Aber insgesamt würde ich sagen das ist noch zu hoch für dich. Mikroprozessorprogrammierung ist nicht einfach, und wenn man die Sprache nicht kann wird das nichts.
knivil schrieb:
Was tun?
Erstmal programmieren lernen.
Willst du nicht hören, stimmt aber leider.
Und nachdem du C kannst kaufst du dir einen Atmel AVR irgendwas und lässt eine LED blinken. Und danach lässt du die LED per Interrupt blinken, was man per Taster an- und abstellen kann. Und dann kannst du mit Sound anfangen. Das dauert so 3-6 Monate. Wenn dir das zu lange dauert gibts eine gute Alternative.
-
Kann man diese Interrupttimer am PC umsetzen?
Alles schon beantwortet.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx
-
also den code von nwp3 hatte ich jetzt nicht die gelegenheit zu probieren, aber so wie ich mir das vorstelle summieren sich die störungen auf. das sleep wird immer länger und länger, weil start nur mit + delay aktualisiert, während gettime schneller wächst. egal,
aber ihr habt recht, ich verzettel mich hier nur, wenn ich so wirre weitermache, bzw. habe mich schon längst verzettelt.