Jak cię złapią, to znaczy, że oszukiwałeś. Jak nie, to znaczy, że posłużyłeś się odpowiednią taktyką.
Wartość ta powinna należeć do przedziału zdefiniowanego w struktu-
rze TIMECAPS. Wywołanie umożliwia optymalizację pracy urządzenia zegara, który po zgromadzeniu niezbędnych informacji od kilku działających programów będzie w stanie zapewniać im najlepszy sposób obsługi. Każde wywołanie funk- cji timeBeginPeriod musi być związane z późniejszym wywołaniem funkcji time- EndPeriod, którą niebawem opiszę. Teraz jesteś gotowy do zaprogramowania zdarzeń zegara: idTimer = timeSetEvent (uDelay, uResolution, CallBackFunc, dwData, uFlag); Jeżeli wystąpi błąd, zwrócona z tego wywołania wartość idTimer będzie równa zero. Od tego wywołania po czasie uDelay milisekund Windows wywoła funkcję CalIBackFunc z dozwolonym błędem, określonym przez uResolution. Wartość uRe- solution musi być większa lub równa rozdzielczości przekazanej do timeBeginPe- riod. Parametr dwData jest wartością definiowaną przez program, przekazywaną później do funkcji CalIBackFunc. Ostatni parametrem może być albo TIME_ONE- SHOT (aby uzyskać pojedyncze wywołanie funkcji CallBackFunc w uDelay mili- ' sekund), albo TIMĘ PERIODIC (aby uzyskać wiele wywołań funkcji CallBackFunc co uDelay milisekund). Chcąc zatrzymać harmonogram jednorazowy zegara, zanim zostanie.wywołana funkcja CallBackFunc, albo harmonogram okresowy, należy wywołać funkcję: timeKillEvent (idTimer); Harmonogramu jednorazowego nie trzeba zabijać, jeśli funkcja CaIlBackFunc zo- stała już wywołana. Po zakończeniu korzystania z zegara, należy wywołać funk- timeEndPeriod (wResolution); z tym samym argumentem co w przypadku timeBeginPeriod. Dwie pozostałe funkcje także zaczynają się prefiksem time. Funkcja dwSysTime = timeGetTime (); , zwraca czas systemowy w milisekundach od pierwszego uruchomierua Windows. Funkcja: timeGetSystemTime (&mmtime. uSize); Rozdział 22: Dźwięk i muryka 1247 wymaga jako pierwszego argumentu wskaźnika do struktury MMTIME, a jako drugiego rozmiaru tej struktury. Struktura MMTIME może w innych okoliczno- ściach posłużyć do odczytarua czasu systemowego w innym formacie niż w mili- sekundach, ale w tych okolicznościach nie może. Tak więc funkcja timeGetSystem- Time jest zbędna. W Windows z poziomu funkcji zwrotnej rue można wywołać dowolnej funkcji. Funkcja zwrotna może wywoływać PostMessage, cztery funkcje zegarowe (time- SetEvent, timeKillEvent, timeGetTime i zbędną timeGetSystemTime), dwie funkcje wyjściowe MIDI (midiOutShortMsg i midiOutLongMsg) oraz funkcję testową Out- putDebugStr. Oczywiście, zegar multimediów został zaprojektowany specjalnie do odtwarza- nia sekwencji MIDI i ma bardzo ograniczone zastosowanie w innych sytuacjach. Można za pomocą PostMessage informować procedurę okna o zdarzeniach zega- ra, po czym procedura okna może sobie zrobić, co tylko zechce, ale jej reakcja nie będzie tak precyzyjnie umiejscowiona w czasie, jak byłaby umiejscowiona reak- cja samej zegarowej funkcji zwrotnej. Funkcja zwrotna ma pięć parametrów, ale używa tylko dwóch z nich: numeru identyfikacyjnego zegara zwróconego z timeSetEvent oraz wartości dwData, prze- kazanej wcześruej w postaci argumentu do timeSetEvent. Moduł DRUM.C w programie DRUMTIME.C wywołuje funkcję DrumSetParams kilka razy: podczas tworzenia okna programu DRUM, gdy użytkownik kliknie macierz albo zmieni położenie paska przewijania, kiedy program załaduje plik .DRM oraz kiedy czyszczona jest macierz. Jedynym argumentem DrumSetParams jest wskaźnik do struktury typu DRUM, zdefiniowanej w pliku nagłówkowym DRUMTIME.H. Struktura ta służy do przechowywania długości trwania kwan- tu czasu (w milisekundach), siły naciskania klawiszy (w uproszczeniu: głośno- ści), liczby kwantów w sekwencji, a także dwóch zestawów czterdziestu siedmiu 32-bitowych liczb całkowitych tworzących macierz (instrumenty perkusyjne x kwanty czasu). Każda z tych liczb odpowiada jednemu uderzeniu w instrument perkusyjny. Struktura typu DRUM w module DRUM.C jest przechowywana w pa- mięci statycznej, do DrumSetParams zostaje przekazany jedynie wskaźnik do struk- tury. Funkcja DrumSetParams kopiuje po prostu jej zawartość. Aby rozpocząć działanie sekwencji, DRUM wywołuje funkcję DrumBeginSequen- ce (w DRUMTTME). Jej jedynym argumentem jest uchwyt okna. Służy on do po- wiadamiania. DrumBeginSequence otwiera urządzenie wyjściowe MIDI Mapper i wysyła komunikaty Program Change, wybierające instrument numer 0 dla ka- nałów MIDI numer 0 i 9. Instrumenty są numerowane od zera, więc 9 oznacza w rzeczywistości kanał MIDI numer 10, czyli perkusyjny. Drugi kanał (a raczej pierwszy) służy do uzyskiwania nut pianina. Następnie (nadal w DrumBeginSe- guence) wywoływane są funkcje timeGetDevCaps i timeBeginPeriod. Żądaną rozdziel- czością, zdefiniowaną za pomocą stałej TIMER RES, jest 5 milisekund, ale zdefi- niowałem makro o nazwie minmax, które ułatwia wyliczanie rozdzielczości w gra- nicach uzyskanych z timeGetDevCaps. Następnie wywoływana jest funkcja timeSetEvent, w której określono czas kwan- tu czasu, wyliczoną rozdzielczość, funkcję zwrotną DrumTimerFunc oraz stałą 1248 Część III: Zagadnienia zaawansowane TIMĘ ONESHOT. W programie DRUMTIME zegar programowany jest na zda- rzerua jednorazowe, a nie okresowe, aby można było dynamicznie zmieniać tem- po podczas trwania sekwencji. Po wywołaniu funkcji timeSetEvent, kiedy minie już zaprogramowany czas zwłoki, urządzenie zegara wywoła funkcję DrumTi- merFunc. Najwięcej dzieje się w funkcji zwrotnej DrumTimerFunc. W zmiennej ilndex zapi- sana jest bieżąca wartość kwantu sekwencji. Funkcja zaczyna się od przesłania komunikatów Note Off dla obecnie odgrywanych dźwięków. Początkowa war- tość ilndex wynosząca -1 zapobiega tej operacji podczas pierwszego uruchamia- nia sekwencji. Następnie zmienna ilndex jest zwiększana, a jej wartość dostarczana do procedu- ry okna programu DRUM za pomocą komunikatu niestandardowego o nazwie WM LISEIRNOTTFY. Argumentowi komunikatu wParam przypisywana jest war- tość ilndex, aby procedura WndProc z DRUM.C mogła uaktualnić położenie "ska- czącej piłeczki". Funkcja DrumTimerFunc kończy się wysłaniem komunikatów Note On do kana- łów syntezatora o numerach 0 i 9 (wartości z kratek są zapamiętywane, aby nuty można było wyłączyć w następnym przebiegu pętli) oraz zaprogramowaniem zegara jednorazowego za pomocą funkcji timeSetEvent. Aby zatrzymać sekwencję, program DRUM wywohzje funkcję DrumEndSequence z jednym argumentem, który może mieć wartość TRUE lub FALSE. Jeżeli ma wartość TRUE, funkcja DrumEndSequence kończy sekwencję od razu: zabijając wszelkie oczekujące zdarzenia zegara, wywołując funkcję timeEndPeriod, wysy- łając komunikaty wyłączające wszystkie nuty do dwóch kanałów MIDI i zamy- kając wyjściowy port MIDI. Funkcja DrumEndSequence jest wywoływana z para- metrem TRUE wtedy, gdy użytkownik zdecyduje się zakończyć program. Jeśli jednak wybierze polecenie Stopped z menu Sequence, program wywoła funk- cję DrumEndSequence z argumentem FALSE. W ten sposób sekwencja przed za-
|
WÄ…tki
|