PROCEDURY DLA GŁOŚNIKA

Dwoma procedurami w tym rozdziale są procedura BEEPER, która faktycznie steruje głośnikiem, oraz procedura polecenia BEEP.

Głośnik jest włączany przez ustawienie na 0 linii D4 podczas instrukcji OUT odnoszącej się do portu '254'. Gdy w podobnej sytuacji linia D4 zostaje ustawiona w stan wysoki, to głośnik jest wyłączany. Stąd 'pisk' może być wytworzony przez regularne zmienianie poziomu linii D4.

Rozważmy teraz dźwięk 'środkowe C', który posiada częstotliwość 261.63 Hz. Aby otrzymać ten dźwięk, głośnik musi być naprzemiennie włączany i wyłączany co 1/523.26 część sekundy. W SPECTRUM zegar systemowy jest ustawiony do pracy przy 3,5 MHz i dźwięk 'środkowe C' będzie wymagał instrukcji OUT wykonywanej z najwyższą dokładnością co 6.689 taktów zegarowych. Ta ostatnia wartość, zmniejszona nieco ze względu na czas niezbędny do wykonania różnych rozkazów, reprezentuje 'długość pętli czasowej' w procedurze BEEPER.
 

PROCEDURA 'BEEPER'

Wejście do tej procedury następuje z parą rejestrów DE zawierającą wartość 'f*t', gdzie dźwięk o danej częstotliwości 'f' ma posiadać czas trwania 't' sekund, i z parą rejestrów HL zawierającą wartość równą liczbie taktów zegara w 'pętli czasu' podzielonej przez '4'.

Np. Dla nuty 'środkowe C' mającej być odtwarzaną przez jedną sekundę DE zawiera +0105 (INT(261.3 * 1)) a HL zawiera +066A (otrzymane z 6,689/4 - 30.125).

03B5 BEEPER       DI                        Wyłącz przerwania na okres trwania 'pisku'.
                  LD    A,L                 Chwilowo zachowaj L.
                  SRL   L                   Każde '1' w rejestrze L ma odpowiadać
                  SRL   L                   '4' taktom zegara, lecz wykonaj
                                            INT (L/4) i zamiast tego zliczaj '16' taktów.
                  CPL                       Wróć do pierwotnej wartości
                  AND   +03                 w L i sprawdź, ile zostało stracone
                  LD    C,A                 przez obliczenie INT (L/4).
                  LD    B,+00
                  LD    IX,+03D1            Adres bazowy pętli czasowej.
                  ADD   IX,BC               Zmień długość pętli czasowej.
                                            Użyj wcześniejszego punktu 
                                            dla każdego '1' utraconego przez wyznaczenie INT (L/4).
                  LD    A,(BORDCR)          Pobierz kolor bieżącego brzegu
                  AND   +38                 i przenieś go do bitów
                  RRCA                      2, 1 1 0 rejestru A.
                  RRCA
                  RRCA
                  OR    +08                 Upewnij się, że wyjście MIC jest wyłączone.

Teraz wejdź to pętli drugiej generacji. Wykonywane jest 'DE' obiegów, tj. obiegów dla każdego okresu dźwięku.

Para rejestrów HL zawiera 'długość pętli czasowej' przy 16 taktach zegara używanych dla każdego '1' w rejestrze L i  1.024 taktach zegara dla każdego '1' w rejestrze H..

03D1 BE-IX+3      NOP                       Dodaj '4' takty zegara dla każdego
03D2 BE-IX+2      NOP                       wcześniejszego punktu wejścia,
03D3 BE-IX+1      NOP                       który jest używany.
03D4 BE-IX+0      INC   B                   Wartości w rejestrach B i C
                  INC   C                   będą pochodziły z rejestrów H i L
                                            - patrz niżej.
03D6 BE-H&L-LP    DEC   C                   'Pętla czasowa'.
                  JR    NZ,03D6,BE-H&L-LP   'BC' * '4' cykle zegara.
                  LD    C,+3F               (Lecz zauważ, że w punkcie połowy okresu
                  DEC   B                   C będzie równe 'L+1'.)
                  JP    NZ,03D6,BE-H&L-LP

Teraz głośnik jest naprzemian włączany i wyłączany.

                  XOR   +10                 Zmień na przeciwny bit 4.
                  OUT   (+FE),A             Wykonaj operację OUT;
                                            pozostawiając brzeg bez zmiany koloru.
                  LD    B,H                 Resetuj rejestr B.
                  LD    C,A                 Zachowaj rejestr A.
                  BIT   4,A                 Skocz, jeśli jest to punkt połowy okresu.
                  JR    NZ,03F2,BE-AGAIN

Po pełnym cyklu para rejestrów DE jest testowana.

                  LD    A,D                 Skocz naprzód, jeśli ostatni
                  OR    E                   pełny okres został
                  JR    Z,03D6,BE-END       już wykonany.
                  LD    A,C                 Pobierz zachowaną wartość.
                  LD    C,L                 Resetuj rejestr C.
                  DEC   DE                  Zmniejsz licznik obiegów.
                  JP    (IX)                Skocz wstecz do wymaganego
                                            punktu startowego pętli.

Ustawiane są parametry dla drugiej połowy cyklu.

03F2 BE-AGAIN     LD    C,L                 Resetuj rejestr C.
                  INC   C                   Dodaj '16' cykli, ponieważ ta ścieżka 
                                            jest krótsza.
                  JP    (IX)                Skocz do tyłu.

Po zakończeniu generacji dźwięku muszą zostać włączone przerwania.

03F6 BE-END       EI                        Włącz przerwania.
                  RET                       Powróć ostatecznie.

PROCEDURA ROZKAZU 'BEEP'

Wejście do tej procedury następuje z dwoma liczbami na stosie kalkulatora. Liczba na szczycie stosu przedstawia 'wysokość' nuty P, a liczba leżąca pod spodem przedstawia jej 'długość' t.

03F8 BEEP         RST   0028,FP-CALC        Użyty zostaje kalkulator zmiennoprzecinkowy 
                                            do manipulacji tymi wartościami - t i P.
                  DEFB  +31,duplicate       t,P,P
                  DEFB  +27,int             t,P,i (gdzie i = INT P)
                  DEFB  +C0,st-mem-0        t,P,i (mem-0 zawiera i)
                  DEFB  +03,subtract        t,P (gdzie p jest częścią ułamkową P)
                  DEFB  +34,stk-data        Umieść na stosie liczbę 'K'.
                  DEFB  +EC,exponent+7C     0.0577622606 (co jest
                  DEFB  +6C,+98,+1F,+F5     nieco poniżej 12*(2^0.5)-1)
                  DEFB  +04,multiply        t,p*K
                  DEFB  +A1,stk-one         t,p*K,1
                  DEFB  +0F,addition        t,p*K+1
                  DEFB  +38,end-calc

Teraz wykonaj kilka testów na i, części całkowitej z 'wysokości' nuty.

                  LD    HL,+5C92            Adres 'mem-0-1st' (MEMBOT).
                  LD    A,(HL)              Pobierz wykładnik i.
                  AND   A                   Zgłoś błąd B, jeśli i nie jest 
                  JR    NZ,046C,REPORT-B    w krótkiej postaci całkowitej.
                  INC   HL                  Skopiuj bit znaku do
                  LD    C,(HL)              rejestru C.
                  INC   HL                  Skopiuj młodszy bajt do
                  LD    B,(HL)              rejestru B i do
                  LD    A,B                 rejestru A.
                  RLA                       Znów zgłoś błąd B, jeśli nie
                  SBC   A,A                 spełnia warunku:
                  CP    C                   -128<=i<=+127
                  JR    NZ,046C,REPORT-B
                  INC   HL
                  CP    (HL)
                  JR    NZ,046C,REPORT-B
                  LD    A,B                 Pobierz młodszy bajt i
                                            przetestuj go dalej.
                  ADD   A,+3C
                  JP    P,0425,BE-i-OK      Zaakceptuj -60<=i<=67.
                  JP    PO,046C,REPORT-B    Odrzuć -128 do -61.

Uwaga: Zakres od +70 do +127 zostanie odrzucony w dalszej części procedury.

Teraz dla każdej 'wysokości' można znaleźć prawidłową częstotliwość.

0425 BE-i-OK      LD    B,+FA               Rozpocznij '6' oktaw poniżej środkowego C.
0427 BE-OCTAVE    INC   B                   Cyklicznie redukuj i w celu znalezienia
                  SUB   +0C                 właściwej oktawy.
                  JR    NC,0427,BE-OCTAVE
                  ADD   A,+0C               Anuluj ostatnie odejmowanie.
                  PUSH  BC                  Zachowaj numer oktawy.
                  LD    HL,+046E            Adres bazowy 'tablicy półtonów'.
                  CALL  3406,LOC-MEM        Rozpatrz tę tablicę i przekaż
                  CALL  33B4,STACK-NUM      'A-tą' wartość na stos kalkulatora (nazwijmy ją C).

Teraz pod uwagę można wziąć część ułamkową 'wysokości'.

                  RST   0028,FP-CALC        t, p*K+1, C
                  DEFB  +04,multiply        t, C*(p*K+1)
                  DEFB  +38,end-calc

Ostateczna częstotliwość f jest znajdowana przez modyfikację 'ostatniej wartości' zgodnie z numerem oktawy.

                  POP   AF                  Pobierz numer oktawy.
                  ADD   A,(HL)              Pomnóż 'ostatnią wartość' przez
                  LD    (HL),A              '2 do potęgi numeru oktawy.
                  RST   0028,FP-CALC        t, f
                  DEFB  +C0,st-mem-0        Chwilowo częstotliwość jest odkładana na bok
                  DEFB  +02,delete          do mem-0.

Teraz uwaga jest kierowana na 'długość'.

                  DEFB  +31,duplicate       t, t
                  DEFB  +38,end-calc
                  CALL  1E94,FIND-INT1      Wartość 'INT t' musi być
                  CP    +0B                 w zakresie od +00 do +0A.
                  JR    NC,046C,REPORT-B

Liczba pełnych okresów w 'pisku' jest dana przez 'f*t', więc teraz ta wartość zostaje obliczona

                  RST   0028,FP-CALC        t
                  DEFB  +E0,get-mem-0       t, f
                  DEFB  +04,multiply        f*t

Wynik jest pozostawiany na stosie kalkulatora, natomiast obliczona zostaje wymagana długość 'pętli czasowej' dla 'pisku';

                  DEFB  +E0,get-mem-0       f*t, f
                  DEFB  +34,stk-data        Wartość '3.5 * 10^6/8'
                  DEFB  +80,four bytes      jest tworzona na szczycie
                  DEFB  +43,exponent +93    stosu kalkulatora.
                  DEFB  +55,+9F,+80,(+00)   f*t, f, 437,500 (dziesiętnie)
                  DEFB  +01,exchange        f*t, 437,500, f
                  DEFB  +05,division        f*t, 437,500/f
                  DEFB  +34,stk-data
                  DEFB  +35,exponent +85
                  DEFB  +71,(+00,+00,+00)   f*t, 437,500/f, 30.125 (dziesiętnie)
                  DEFB  +03,subtract        f*t, 437,500/f - 30.125
                  DEFB  +38,end-calc

Uwaga: Wartość '437,500/f' daje długość 'połowy okresu' nuty skróconej o 30.125' dla '120.5' taktów, w czasie których dźwięk jest tworzony oraz są obsługiwane liczniki.
Wartości te mogą teraz zostać przeniesione do odpowiednich rejestrów.

                  CALL  1E99,FIND-INT2      Wartość 'pętli czasowej' zostaje
                  PUSH  BC                  umieszczona w parze rejestrów BC i zachowana.

Uwaga: Jeśli wartość dla pętli czasowej jest zbyt duża, to powstanie błąd (powrót poprzez ERROR-1); w ten sposób unika się 'wysokości' od '+70 do +127'.

                  CALL  1E99,FIND-INT2      Wartość 'f*t' trafia do pary rejestrów BC.
                  POP   HL                  Przenieś ją do pary rejestrów HL.
                  LD    D,B                 Przenieś wartość 'f*t'
                  LD    E,C                 do pary rejestrów DE.

Jednakże przed wykonaniem 'pisku' sprawdź wartość 'f*t'.

                  LD    A,D                 Wróć, jeśli 'f*t' dało
                  OR    E                   wymagany wynik
                  RET   Z                   'brak taktów'.
                  DEC   DE                  Zmniejsz liczbę taktów
                  JP    03B5,BEEPER         i skocz do procedury BEEPER
                                            (wykonując co najmniej jeden obieg).

Raport B - liczba całkowita poza zakresem

046C REPORT-B     RST   0008,ERROR-1        Wywołaj procedurę obsługi
                  DEFB  +0A                 błędów.

TABLICA 'PÓŁTONÓW'

Ta tablica przechowuje częstotliwości dwunastu półtonów w oktawie.

                  częstotliwość w Hz.       nuta
046E DEFB         +89,+02,+D0,+12,+86       261.63 C
     DEFB         +89,+0A,+97,+60,+75       277.18 C#
     DEFB         +89,+12,+D5,+17,+1F       293.66 D
     DEFB         +89,+1B,+90,+41,+02       311.12 D#
     DEFB         +89,+24,+D0,+53,+CA       329.63 E
     DEFB         +89,+2E,+9D,+36,+B1       349.23 F
     DEFB         +89,+38,+FF,+49,+3E       369.99 F#
     DEFB         +89,+43,+FF,+6A,+73       392 G
     DEFB         +89,+4F,+A7,+00,+54       415.30 G#
     DEFB         +89,+5C,+00,+00,+00       440 A
     DEFB         +89,+69,+14,+F6,+24       466.16 A#
     DEFB         +89,+76,+F1,+10,+05       493.88 H

PROCEDURA 'NAZWA PROGRAMU' Z ZX81

Poniższa procedura odnosi się do ZX81 i nie została usunięta, gdy program został przepisany dla SPECTRUM.

04AA DEFB         +CD,+FB,+24,+3A
     DEFB         +3B,+5C,+87,+FA
     DEFB         +8A,+1C,+E1,+D0
     DEFB         +E5,+CD,+F1,+2B
     DEFB         +62,+6B,+0D,+F8
     DEFB         +09,+CB,+FE,+C9

 



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.