Informatyka 
 
Syntezator – program – część 6
Narcyz
Nasz układ dekodowania komunikatów MIDI, ma już gotowy sekwencer, możemy jeszcze do niego dołożyć arpegiator – zestaw procedur pozwalający grać akord – po jednej nucie.

Współczesne syntezatory mają bardzo rozbudowane układy arpeggia, które można uczyć, lub które posiadają bardzo wiele schematów. Nic nie stoi na przeszkodzie by czytelnik (lub autor, jeśli wymyśli jak to można łatwo obsłużyć) coś takiego napisał. Na początek jednak będzie musiał nam wystarczyć arpegiator posiadający tylko trzy, najbardziej przydatne i popularne – schematy:

  • Nuty grane są od najniższej nuty po kolei w górę, gazu dojdziemy do końca – zmieniamy kierunek.
  • Nuty grane są od najwyższej do najniższej.
  • Nuty grane są od najniższej do najwyższej, po czym zmieniają kierunek i grane są „w dół”, po czym znów „w górę”

Wyboru odpowiedniego programu użytkownik będzie dokonywał przełącznikiem.

Nie będziemy to rozważać, zostawiając to na następny odcinek, kiedy zaczniemy wszystko integrować:

  • Kiedy należy zacząć grać arpeggio?
  • Czym je taktować
Warto jednak zastanowić się nad tym jak zareagujemy na sytuacje dodawania naciśniętych klawiszy do granego arpeggia, lub ich zwalniania. Warto się także zastanowić co mamy zrobić gdy ktoś w czasie gry zmieni kierunek arpeggia.

Jeśli nie będziemy się przejmowali naciskaniem i puszczaniem klawiszy w czasie gry, wędrując zawsze po aktualnie naciśniętych klawiszach – nie musimy zapamiętywać akordu, a jedynie szukać poprzedniego i następnego naciśniętego klawisza, co znacznie uprości nam program, zwłaszcza że procedury te mamy przygotowane (pisaliśmy o nich w poprzednim odcinku). W takim przypadku musimy jedynie pamiętać jaki klawisz jest aktualnie grany i w którym kierunku powinniśmy szukać następnego:

			.CSEG

			.def	R_ARPEGIO = r23
			; contain last played key or $7f (none)
			; bit 7 indicated direction - 0: up 

Użyjemy to pojedynczego rejestru. Siedem bitów przeznaczymy na numer klawisza, a ostatni - bit znaku na kierunek.

Potrzebujemy zainicjować arpegiator. Do rejestru w którym pamiętamy stan arpeggia zapiszemy specjalna wartość która będzie oznaczała – że funkcja pobierająca następny klawisz:

ARP_init:		ldi	r16, $7f
			mov	R_ARPEGIO, r16
			ret 

Funkcja czytająca kolejną zagraną nutę – będzie zwracała ją w rejestrze r16. Jeśli żaden klawisz nie jest naciśnięty – funkcja zwróci wartość 255 (szestanstkowo –ff). Odpowiedni warunek musimy sprawdzić na początku:

ARP_read:		tst	PRESSED_COUNT
			brne	arp_i
arp_nothing:		ldi	r16, $ff
			ret

Sprawdźmy teraz, czy nie jest to pierwsza grana nuta tego akordy – to znaczy czy nie jest to pierwsze wywołanie tej funkcji po inicjalizacji. Jeśli nie – skoczymy dalej.

arp_i:			mov	r16, R_ARPEGIO
			andi	r16, $7f
			cpi	r16, $7f
			brne	arp_01

Teraz sprawdźmy jaki jest wybrany program, sprawdzając które przełączniki są włączone. Konstruując instrument, zdecydowałem się na pojedynczy przełącznik trójpozycyjny – jako najbardziej intuicyjny. Tu musimy jedynie sprawdzić – czy nie jest on w pozycji „w dół”:

			; init arpegio
			mov	r16, SWITCHES
			andi	r16, $08
			brne	arp_i_down

Jeśli nie – to rozpoczynamy od dołu klawiatury – szukając od zera. Niestety – zero w pewnych przypadkach także może być naciśnięte, a funkcja getNext – zwraca następny. Dlatego sprawdzimy jeszcze czy przed znalezionym nie ma poprzedniego: To co znaleźliśmy do grany klawisz:

			; init up
arp_i_up:		push	r17
			ldi	r16, 0
			rcall	keymap_getNext
			push	r16
			rcall	keymap_getPrev
			cpi	r16, $ff
			pop	r17
			brne	arp_first
			mov	r16, r17
arp_first:		pop	r17
arp_set_u:		mov	R_ARPEGIO, r16
			ret

Znalezienie najwyższej granej nuty nie wymaga tego dodatkowego kroku, ponieważ możemy zapytać o nutę poprzedzającą taką która już nie istnieje. Nasza mapa pracuje na wartościach do 127, a najwyższa nuta ma numer 120:

arp_i_down:		ldi	r16, 127
			rcall	keymap_getPrev
arp_set_d:		ori	r16, $80
			mov	R_ARPEGIO, r16
			andi	r16, $7f
			ret

Przy liczeniu kolejnej granej nuty – musimy sprawdzić – czy gramy w górę czy w dół:

arp_01:			; play next note
			mov	r16, R_ARPEGIO
			andi	r16, $80
			brne	arp_prev

Jeśli gramy w górę, sprawdźmy czy muzyk nie przełączył arpegiatora w trym „w dół” – a jeśli tak – mamy grać w dół

arp_next:		; check if down is not forced
			mov	r16, SWITCHES
			andi	r16, $08
			brne	arp_prev

Teraz wystarczy wywołać funkcję zwracającą następną nutę z mapy naciśniętych klawiszy, i jeśli nie zwróci informacji o nie znalezieniu – zwracamy graną nutę, i zapamiętujemy jej wartość:

			mov	r16, R_ARPEGIO
			andi	r16, $7f
			rcall	keymap_getNext
			cpi	r16, $ff
			brne	arp_set_u

Jeśli skończyliśmy – nie ma wyższych nut – sprawdzamy czy jest sens coś grać, to znaczy czy naciśniętych jest więcej niż jeden klawisz, i jeśli tak – inicjalizujemy granie w górę (a to mamy już napisane}, chyba że wybrano granie w górę i w dół – wtedy zapamiętujemy klawisz wraz z dodatkową informacją – mamy od teraz grać w dół:

			mov	r16, PRESSED_COUNT
			cpi	r16, 1
			breq	arp_one
					
			mov	r16, SWITCHES
			andi	r16, $10
			brne	arp_i_up

Dokładnie ten sam scenariusz powtarzamy pisząc program poszukiwania niższej od aktualnie granej – nuty

{arp_prev:		; check if up is not forced
			mov	r16, SWITCHES
			andi	r16, $10
			brne	arp_next

			mov	r16, R_ARPEGIO
			andi	r16, $7f
			rcall	keymap_getPrev
			cpi	r16, $ff
			brne	arp_set_d
					
			mov	r16, PRESSED_COUNT
			cpi	r16, 1
			breq	arp_one
					
			mov	r16, SWITCHES
			andi	r16, $08
			brne	arp_i_down
			rjmp	arp_next

arp_one:		mov	r16, R_ARPEGIO
			andi	r16, $7f
			ret

 
Opinie
 
Facebook
 
  
22251 wyświetleń

numer 5/2016
2016-05-01

Od redakcji
Aktualności
Ekologia
Ekonomia
Elektronika
Fizyka
Kącik poezji
Literatura
Matematyka
Polityka
Rozmaitości
Sztuka życia

nowyOlimp.net na Twitterze

nowy Olimp - internetowe czasopismo naukowe dla młodzieży.
Kolegium redakcyjne: gaja@nowyolimp.net; hefajstos@nowyolimp.net