kategoria: ANSI C
[#1] [C] odgrywanie sampla tylko za pomocą rejestrów
Szukam prawilnego przykładu w C jak odegrać sampla. Najlepiej z wyjaśnieniem. Od razu mówie że przykłady w audio.device to już mam i działają. przykład z przerwaniem audio też mam ale w asm.
[#2] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #1

Czyli tym razem chodzi o kod bezpośrednio odwołujący się do rejestrów Pauli? Bo jeżeli "prawilnie" oznacza systemowo, to albo audio.device albo AHI...
[#3] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Krashan, post #2



kod bezpośrednio odwołujący się do rejestrów Pauli



A to będzie dalej jeszcze C?
[#4] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@_DiskDoctor_, post #3

Oczywiście, że tak. W języku C możesz uprawiać równie dobrze "ciężką rzeźbę po rejestrach" jak w asemblerze. A nawet wygodniej, niż w asemblerze. Tu jest bardzo dobry przykład.

Ostatnia aktualizacja: 24.07.2024 12:48:41 przez Krashan
1
[#5] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Krashan, post #2

Bezpośrednio walenie po rejestrach. Gdzies dawno temu miałem przykład w asm od Don Adana ale coś nie mogę znaleźć.
[#6] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #5

Tutaj. Ostatnio o to samo go pytałem, a właściwie o obsługę przerwania zatrzymującego zapętlenie odtwarzania sampla. Post 12+13.

Ostatnia aktualizacja: 24.07.2024 12:58:49 przez tukinem
1
[#7] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Krashan, post #4

No ale niektóre działania w C czy C++, kłócą się z definicją języka wysokopoziomowego.
[#8] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@tukinem, post #6

To nie to. Potrzebuje bez przerwania audio irq. Bo bym musiał ogarnąć vbr i inne rzeczy związane z przerwaniami, jak zapamiętanie przerwania i potem oddanie.
[#9] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #8

Możesz popatrzeć jak ptplayer to robi, jeśli lubisz asm, a jak wolisz C to mam wersję C ;)

https://github.com/AmigaPorts/ACE/blob/master/src/ace/managers/ptplayer.c#L1148

trochę tam jest dodatkowej logiki związanej z playerem, ale wierzę że przez nią przebrniesz i wyłuskasz co potrzebujesz. pChannelReg to wskaźnik na zestaw rejestrów konkretnego kanału. Pamiętaj że wyłączenie DMA kanału nie powoduje przestanie odtwarzania sampla, tylko dane w kanale przestają być aktualizowane - najlepiej zapętlić kanał na zerowym wordzie i/lub zmienić mu volume na zero.

@DiskDoctor. Wpisywanie wartości w pola struktur jest bazalną operacją języka C. Rejestry chipsetu są wystawione jako gigantyczna struktura, do której pól możesz sobie wpisywać wartości. Gdzie tu robienie czegoś niezgodnie z C? Cały kod w przemyśle embedded tak działa.

Ostatnia aktualizacja: 24.07.2024 14:04:36 przez teh_KaiN
1
[#10] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #8

To moze byc jako baza, choc pod systemem nie trzeba ustawiac dff000.
Tylko rts zamiast rte jak pod systemem.
No i bodaj SetIntVector sie uzywa, o ile pamietam.
7 glosowe playery tak maja, bodaj ten sample player do tej wegierskiej gry w stylu Another World czy Flashbaka (onEscapee) i custom moduly, ktore odgrywaja sample jako muzyke. Zalezy czy chcesz z chipu czy z fastu sample odgrywac.
Mozesz sobie zrodla poprzegladac.
[#11] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Don_Adan, post #10

Chcę z chipu odgrywać
[#12] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #11

To chyba Crazy Cars 1/2 lub Fire and Forget 1/2 to byla muzyka (sampel odgrywany z chipu).
O ile dobrze pamietam.
Bo przy wiekszych samplach to odgrywalem je juz z fastu.
[#13] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #8

Przebrany kawałek kodu dla double buffer sample bez przerwań

lea	CUSTOM,a4

	;turn off
	move.w	#DMAF_AUDIO,dmacon(a4)
	move.w	#$FF,adkcon(a4)		;modulation off
	move.w	#INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,intena(a4)

	bsr.w	SetAudio	;set audio1 (vol, per, len)

	;start audio
	move.w	#DMAF_SETCLR!DMAF_MASTER!DMAF_AUD0!DMAF_AUD1,dmacon(a4)

.loop	eor.w	#1,d7		;change buffer
	bsr.w	ReadFrame	;read to hidden buffer
	bne.s	.end

	bsr.w	SetAudio	;set audio for hidden frame

	;wait for end of actual audio
	move.w	#INTF_AUD0!INTF_AUD1,intreq(a4)
.wait	move.w	intreqr(a4),d0
	and.w	#INTF_AUD0!INTF_AUD1,d0
	beq.s	.wait

	btst	#10,potinp(a4)	;check right mouse button
	beq.s	PlayEnd

	;wait for vbl
	move.w	#INTF_VERTB,intreq(a4)
.vbl	move.w	intreqr(a4),d0
	and.w	#INTF_VERTB,d0
	beq.s	.vbl

	bra.s	.loop

	;wait for end of last frame audio
.end	move.w	#INTF_AUD0!INTF_AUD1,intreq(a4)
.wait2	move.w	intreqr(a4),d0
	and.w	#INTF_AUD0!INTF_AUD1,d0
	beq.s	.wait2

PlayEnd	;stop audio
	move.w	#DMAF_AUDIO,dmacon(a4)
[#14] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@cholok, post #13

ten kod sprawdza koniec sampla?

Ja napisałem sobie taką procedurkę, gdzie mogę wybierać kanał odgrywania sampla, no ale niestety jest zapętlony:
;///////////////////////////////////////////////////

Statement PLAYSOUND{soundaddr.l ,  kanal.w , vol.w}

SetValueForDMACON
  MOVE.l #%1000001000000000,d3
  TST.b d1    : BEQ.b 'AUD0
  CMP.b #1,d1 : BEQ.b 'AUD1
  CMP.b #2,d1 : BEQ.b 'AUD2
  CMP.b #3,d1 : BEQ.b 'AUD3
  BRA 'DALEJ
'AUD0
  ORI.b #%1,d3
  BRA 'DALEJ
'AUD1
  ORI.b #%10,d3
  BRA 'DALEJ
'AUD2
  ORI.b #%100,d3
  BRA 'DALEJ
'AUD3
  ORI.b #%1000,d3


'DALEJ

;NR KANALU
  LSL.b #4,d1


;TYP DZWIEKU
  MOVE.l d0,a0


;BAZA HARDWARE
  LEA $dff000,a6
  ADDA.l d1,a6
  ADDA.l #$A0,a6


  MOVE.l (a0),(a6)                  ; _data.l      AUDxLCN

  MOVE.w 6(a0),4(a6)                ; _length.w    AUDxLEN

  MOVE.w 4(a0),6(a6)                ; _period.w    AUDxPER

  MOVE.w d2,8(a6)                   ; volume.w     AUDxVOL

  MOVE.w d3,$dff096                 ;              DMACON

End Statement



;///////////////////////////////////////////////////



PLAYSOUND{Addr Sound(0) , 0 , 63}   ; kanal 0
PLAYSOUND{Addr Sound(0) , 1 , 63}   ; kanal 1


Ostatnia aktualizacja: 25.07.2024 00:41:29 przez tukinem
[#15] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@tukinem, post #14

Jak chcesz to mozesz tak zrobic, troche krocej i szybciej. Ogolnie im mniej skokow w kodzie tym lepiej/szybciej.

;///////////////////////////////////////////////////

Statement PLAYSOUND{soundaddr.l ,  kanal.w , vol.w}

SetValueForDMACON
  MOVEQ #1,d3
  TST.b d1    : BEQ.b 'DALEJ1
 MOVEQ #2,d3
  CMP.b #1,d1 : BEQ.b 'DALEJ
 MOVEQ #8,d3
  CMP.b #2,d1 : BNE.b 'DALEJ
 MOVEQ #4,d3
 
'DALEJ

;NR KANALU
  LSL.b #4,d1
'DALEJ1

;TYP DZWIEKU
  MOVE.l d0,a0


;BAZA HARDWARE
  LEA $dff0A0,a6
  ADDA.w d1,a6
 ORI.w #%1000001000000000,d3

  MOVE.l (a0),(a6)                  ; _data.l      AUDxLCN

  MOVE.w 6(a0),4(a6)                ; _length.w    AUDxLEN

  MOVE.w 4(a0),6(a6)                ; _period.w    AUDxPER

  MOVE.w d2,8(a6)                   ; volume.w     AUDxVOL

  MOVE.w d3,$dff096                 ;              DMACON

End Statement



;///////////////////////////////////////////////////



PLAYSOUND{Addr Sound(0) , 0 , 63}   ; kanal 0
PLAYSOUND{Addr Sound(0) , 1 , 63}   ; kanal 1


Ogolnie to i ta procedure da sie poprawic.
Raczej zamiast .b powinienes uzywac .w, a zamiast .l to .w. Byloby czytelniej, a szybkosc taka sama.
Operacje na .l sa wolniejsze na 68000 niz operacje na .w no i zajmuja 2 bajty wiecej w pamieci, o ile nie dzialaja na rejestrach.

Ostatnia aktualizacja: 25.07.2024 09:15:00 przez Don_Adan
[#16] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Don_Adan, post #12

@Don Adan
To chyba Crazy Cars 1/2 lub Fire and Forget 1/2 to byla muzyka (sampel odgrywany z chipu).
O ile dobrze pamietam.

Obejrzałem to i to nie to o co mi chodziło. Tam korzysta się z przerwań audio jak dobrze zrozumiałem.

@cholok
Dzięki wielkie, obadam to. Chociaż ja jestem noga z audio harware, nie mogę skumać do końca jak to działa z tym audio hardware.

Znalazłem na EAB temat, który może mi pomóc link

Przegrzebałem dysk i znalazłem coś takiego i chyba dostałem to dawno temu od Don Adana, przy konwersji Solomons Key z Atari ST. Nie do końca jeszcze to ogarniam. Jakby ktoś mi to wytłumaczył łopatologicznie to byłbym wdzięczny.

include	hardware/custom.i

;-----------------------------------------------------------------------------
	XDEF	_PlaySample

;a0 - address of sample (CHIP memory)
;d3 - length of sample
;a2 - address of empty sample

_PlaySample:
		movem.l	D0-A6,-(A7)

		lea	$dff000,A5		; load CustomBase
		lea	$b0(a5),a1		; channel
		moveq	#2,D2
.StopDMA
		move.b	vhposr(A5),d1
.WaitLine1
		cmp.b	vhposr(A5),d1			; sync routine to start at linestart
		beq.s	.WaitLine1
.WaitDMA1
		cmp.b	#$16,vhposr+1(A5)		; wait til after Audio DMA slots
		bcs.s	.WaitDMA1
		move.w	#1,6(A1)

		move.w	dmaconr(A5),d0			; get active channels
		and.w	d2,d0
		move.w	d0,d1
		lsl.w	#7,d0
		move.w	d0,intreq(A5)			; clear requests
		move.w	d1,dmacon(A5)			; stop channels
.WaitStop
		move.w	intreqr(A5),d1			; wait until all channels are stopped
		and.w	d0,d1
		cmp.w	d0,d1
		bne.s	.WaitStop
.Skip

; Here you must set the oneshot-parts of the samples you stopped before

		move.l	A0,(A1)			;address of sample
		move.w	d3,4(A1)		;lenght
		move.w	#160,6(A1)		;11050
		move.w	#$40,8(A1)

		move.b	vhposr(A5),d1
.WaitLine2
		cmp.b	vhposr(A5),d1			; sync routine to start at linestart
		beq.s	.WaitLine2
.WaitDMA2
		cmp.b	#$16,vhposr+1(A5)		; wait til after Audio DMA slots
		bcs.s	.WaitDMA2
.StartDMA
		move.w	dmaconr(A5),d0			; get active channels
		not.w	d0
		and.w	D2,D0

		move.w	d0,d1
		or.w	#$8000,d1
		lsl.w	#7,d0
		move.w	d0,intreq(A5)			; clear requests
		move.w	d1,dmacon(A5)			; start channels
.WaitStart
		move.w	intreqr(A5),d1			; wait until all channels are running
		and.w	d0,d1
		cmp.w	d0,d1
		bne.s	.WaitStart

		move.b	vhposr(A5),d1
.WaitLine3
		cmp.b	vhposr(A5),d1			; sync routine to start at linestart
		beq.s	.WaitLine3
.WaitDMA3
		cmp.b	#$16,vhposr+1(A5)		; wait til after Audio DMA slots
		bcs.s	.WaitDMA3


		move.l	A2,(A1)
		move.w	#1,4(A1)

		movem.l	(A7)+,D0-A6
		rts

;-----------------------------------------------------------------------------
1
[#17] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #8

Z przerwaniami w C jest o wiele mniej roboty:
struct Custom *custom = (void*)0xdff000;
LONG	audiosig = -1;

void StartAudio( void ) { // tu trzeba jeszcze ac_ptr, u mnie były stałe
	custom->aud[0].ac_vol = ioregs.vol;
	custom->aud[1].ac_vol = ioregs.vol;
	custom->aud[0].ac_per = ioregs.period;
	custom->aud[1].ac_per = ioregs.period;
	custom->intreq = INTF_AUD1;
	custom->intena = INTF_SETCLR|INTF_AUD1;
	custom->dmacon = DMAF_SETCLR|DMAF_MASTER|DMAF_AUD0|DMAF_AUD1;
}

void AbortAudio( void ) {
	custom->dmacon = DMAF_AUD0|DMAF_AUD1;
	custom->intena = INTF_AUD1;
	custom->intreq = INTF_AUD1;
}

void __interrupt __saveds AudioServer( void ) {
	custom->intreq = INTF_AUD1;
	Signal( mytask, 1<<audiosig );
}

struct Interrupt *oldaudiovec = NULL;
struct Interrupt audiovec = {
	NULL, NULL, NT_INTERRUPT, 5, "audio_int",
	NULL, (void(*)(void))&AudioServer
};

	//* początek
	audiosig = AllocSignal( -1 );
	if ( audiosig == -1 )
		die("no free signals");

	oldaudiovec = SetIntVector( INTB_AUD1, &audiovec );

	...
	// jeśli czekasz na koniec sampla, jeśli nie to ogarniasz inne funkcje obsługi sygnałów
	Wait( 1<<audiosig );


	// koniec
	SetIntVector( INTB_AUD1, oldaudiovec );
	if ( audiosig != -1 ) {
		FreeSignal( audiosig );
		audiosig = -1;
	}
[#18] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #16

O ile rozpoznaje to Petera Kunatha (wspolautora DeliPlayera) to bylo.
Czasami tego uzywalem, ale w przerobionej formie.

Edycja.
Zreszta ten kawalek tez jest juz troche przerobiony, poznaje w nim swoje zmiany.
Bodaj w playerze do Sonic Arrangera tego uzylem, zeby odgrywac bardzo krotkie (parenascie bajtow) sample, bo oryginalny odgrywacz cos mi sie nie podobal.


Ostatnia aktualizacja: 25.07.2024 12:25:00 przez Don_Adan
[#19] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #16

Audio DMA działa tak, że adresy sampla kopiowane są wewnętrznego bufora i po dograniu do końca znowu są kopiowane dopóki włączone jest DMA. Przy dojściu do końca ustawiane są flagi intreq. Odegranie sampla:
- ustawienie pointers, volume, period, length
- włączenie DMA
- poczekanie aż nastąpi skopiowanie adresów prze Paulę, tu jest kilka metod:
-- użycie przerwania
-- poczekanie na wyświetlenie kilka linii (vhpors)
-- programowa pętla (zależne od CPU)
- wpisanie nowych adresów
-- dla zapętlonego sampla, wartości zapętlenia
-- dla pojedynczego: length=1 i adres dla wyzerowanego słowa (odgrywanie zerowego sampla)
- odczyt intreqr (ręcznie lub przerwanie) jak sample osiągnął koniec co nie kończy odgrywania
[#20] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Don_Adan, post #18

Ogolnie to byl kod pod DMA wait.
Czyli taki bardziej do miksowania muzyki i SFX.
Wedlug mnie do odgrywania samych sampli to pod systemem najlepszy jest Audio Vector.
Czyli przerobiona procedura Rossa z postu 6, bo pod systemem to moze byc jeszcze krotsze i o paredziesiat cyklow szybsze, przy uzyciu SetAudioVector, jak sie ladna strukture napisze, wykorzystujac IS_Data, o ile dobrze pamietam nazwe.
[#21] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Don_Adan, post #20

@Don Adan
Ogólnie, to jak zwykle, źle i za szybko opisałem co potrzebuje.
Sytuacja jest taka. Potrzebuje odgrywanie sample do gry. Nie będę robił tego z użyciem systemu.
I doszedłem do takiego rozwiązania tyle że nie wiem czy jest poprawne, ale działa.

include	hardware/custom.i

;-----------------------------------------------------------------------------
	XDEF	_PlaySample

;a0 - address of sample (CHIP memory)
;d3 - length of sample
;a2 - address of empty sample

_PlaySample:
		movem.l	d0-a6,-(a7)

		lea	$dff000,a5
		lea	$A0(a5),a1		; channel 0

		move.l	a0,(a1)		;address of sample
		move.w	d3,4(a1)		;size in words
		move.w	#160,6(a1)	;period
		move.w	#$40,8(a1)       ;volume

		move.w	#$8001,dmacon(a5) ;start

		move.b	vhposr(A5),d1
.WaitLine3
		cmp.b	vhposr(A5),d1			; sync routine to start at linestart
		beq.s	.WaitLine3
.WaitDMA3
		cmp.b	#$16,vhposr+1(A5)		; wait til after Audio DMA slots
		bcs.s	.WaitDMA3

 ;set empty sfx
		move.l	A2,(A1)
		move.w	#1,4(A1)

		movem.l	(A7)+,D0-A6
		rts
;-----------------------------------------------------------------------------

I pytanie czy ten wait, który czeka aż dma audio zostanie zapisany, czy to można jakoś ograć jedną pętlą.
[#22] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #21

Nie wiem jak to bedzie dzialac jezeli pare sampli bedzie odgrywanych na raz.
Tzn, jeden efekt naklada sie na drugi, bez skonczenia odgrywania poprzedniego sampla, czy czasem nie bedziesz mial wtedy trzaskow ?
No i zwykle dla efektow to sie czwartego kanalu uzywa, chyba ze gra jest bez muzyki i kazdy kanal moze wtedy odgrywac sfx.
No i poprawilbym zuzycie stosu.
[#23] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@Don_Adan, post #22

Racja, racja. Musze porobić więcej testów. Stos i inne drobnostki poprawię. Dzięki
[#24] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@asman, post #21

Tak się zastanawiam co ma pozycja promienia wizji (VHPOSR) do odgrywanego dźwięku, ale chyba tak głęboko lepiej nie wnikać, bo idzie zwariować
[#25] Re: [C] odgrywanie sampla tylko za pomocą rejestrów

@tukinem, post #24

Wtedy dopiero DMA jest gotowe na przyjecie nowych danych, o ile dobrze pamietam.
Mozna czekac dluzej, ale to jest strata czasu.
Zwykle sie 8 linii czeka. A kiedys to byly puste dbf, ktore tylko na 68000 7 MHz byly ok.
Albo uzywa sie timera.
W sumie ktos moze zrobic testy, co jest szybsze/lepsze, timer czy metoda Petera Kunatha.
Tylko jak uzywa sie timera to tez sie zuzywa cos (timer) co mozna by uzyc do czegos innego w grze.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem