Help with sample mixing routine please

All about modules/digital tunes in a variety of tracker & sampled formats

Moderators: lotek_style, Moderator Team

uko
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 125
Joined: Sun Aug 25, 2019 6:45 pm
Location: France

Re: Help with sample mixing routine please

Post by uko »

unseenmenace wrote: Sat Oct 30, 2021 10:51 pm That's really cool, I'll be interested to hear how big the hit in sound quality and volume is. Not sure if I can make use of movep for buffering in my routine since it needs to be pretty adaptable for different output devices but I'll give it some thought :)
Concerning volume, a "classical" 2 voices mixing routine generally uses samples converted to 7 bits (so as the result has 8 bits).
With the add.l approach (or add.w as mentionned by dbug), you must convert to 6 bits (and unsigned) so as the addition works correctly. Therefore the amplitude of the signal will be divided by 2, so a loss of 6dB.

In the repository containing my replay code, there are also already compiled examples (require STe and probably 1 or 2 MBytes of RAM, I can't remember), using the different techniques I have implemented (and also different MOD files for some), so you will be able to compare the sound quality difference. They are here: https://github.com/Uko-TAL/STE_FullScre ... master/Bin
And the two following test programs use the same MOD file and allow to compare the two mixing techniques:
- MPL.TOS: mix using the move.l, add.l and movep.l technique
- MPFSOV.TOS: mix using move.b, add.b, and move.b
(When launched, wait few seconds until a text is displayed, then press the space bar)

And it is the move.l, add.l and movep.l option that I have also used in my latest demo (see my signature below).
David aka Uko, from T.AL
Take a look at our last STe demo ! The Star Wars Demo and to its "making of"
https://github.com/Uko-TAL
User avatar
unseenmenace
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2048
Joined: Tue Sep 21, 2004 9:33 pm
Location: Kent, UK

Re: Help with sample mixing routine please

Post by unseenmenace »

Dbug wrote: Sun Oct 31, 2021 6:03 am you could just do a pass with simple move.w (an)+ (or even possibly movem.w to batch write registers) for the first channel, and then only use the optimized "odd access" code for the second channel.
Makes sense, I'll just have slightly different macros for DMA Left and DMA Right, and do the right channel first as words, then fill the gaps with the left channel afterwards. Cheers :)

uko wrote: Sun Oct 31, 2021 8:48 pm In the repository containing my replay code, there are also already compiled examples (require STe and probably 1 or 2 MBytes of RAM, I can't remember), using the different techniques I have implemented (and also different MOD files for some), so you will be able to compare the sound quality difference. They are here: https://github.com/Uko-TAL/STE_FullScre ... master/Bin
And the two following test programs use the same MOD file and allow to compare the two mixing techniques:
- MPL.TOS: mix using the move.l, add.l and movep.l technique
- MPFSOV.TOS: mix using move.b, add.b, and move.b
(When launched, wait few seconds until a text is displayed, then press the space bar)

And it is the move.l, add.l and movep.l option that I have also used in my latest demo (see my signature below).
Thanks, I'll have a look at that :)


For anyone that's interested, I'm currrently working on implementing volume adjustment. I'm only having 16 volume levels for now at least and I'm writing a bit of code that produces 256 separate tables, one for each combination of volumes for the 2 channels being mixed. Each table is 256 x 256 bytes and contains every combination of sample bytes adjusted for that specific combination of volumes. That way I just have to determine which table should be used before each buffering session, therefore having little if any impact on buffering speed. Hope that makes sense?
UNSEEN MENACE
2 original ST's, several STFM's, 2 STE's, a TT and a 14MB Falcon,
a Lynx 2 and Jaguar with JagCD
User avatar
unseenmenace
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2048
Joined: Tue Sep 21, 2004 9:33 pm
Location: Kent, UK

Re: Help with sample mixing routine please

Post by unseenmenace »

unseenmenace wrote: Mon Nov 08, 2021 1:15 pm For anyone that's interested, I'm currrently working on implementing volume adjustment. I'm only having 16 volume levels for now at least and I'm writing a bit of code that produces 256 separate tables, one for each combination of volumes for the 2 channels being mixed. Each table is 256 x 256 bytes and contains every combination of sample bytes adjusted for that specific combination of volumes. That way I just have to determine which table should be used before each buffering session, therefore having little if any impact on buffering speed. Hope that makes sense?
So I've just realised this would use WAY more memory than I have available so I'm going to have a slight re-think :D
UNSEEN MENACE
2 original ST's, several STFM's, 2 STE's, a TT and a 14MB Falcon,
a Lynx 2 and Jaguar with JagCD
User avatar
unseenmenace
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2048
Joined: Tue Sep 21, 2004 9:33 pm
Location: Kent, UK

Re: Help with sample mixing routine please

Post by unseenmenace »

So in the end I needed a couple more registers so I had to have less of them used globally by the YM playback code and just stack a couple of them for each Timer A interrupt. This meant I could have addresses of 2 volume adjustment tables handy in a3 and a4, which were generated from a set of 16 fractional multipliers at the start of the program:

Code: Select all

bufdmav	MACRO
*** a0 = mixing table address
*** a1 = sample 1 address
*** a2 = sample 2 address
*** a3 = sample 1 vol table address
*** a4 = sample 2 vol table address
*** a5 = destination buffer address
*** d1 = sample 1 increment fraction
*** d2 = sample 2 inc fraction (upper) & sample 1 inc integer (lower)
*** d3 = sample 2 increment integer
*** d4 = sample 1 offset fraction
*** d5 = sample 2 offset fraction (upper) & sample 1 offset integer (lower)
*** d6 = sample 2 offset integer (lower)
	move.b	(a1,d5),d0		get ch1 sample byte
	ext.w	d0
	move.b	(a3,d0),d0		get volume adjusted byte
	ext.w	d0
	move.b	(a2,d6),d7		get ch2 sample byte
	ext.w	d7
	move.b	(a4,d7),d7		get volume adjusted byte
	ext.w	d7
	add.w	d7,d0			add sample words
	move.b	0(a0,d0),(a5)		get result and write to buffer
	addq.l	#2,a5			skip over other DMA channel
	add.w	d1,d4			add sam1 inc fraction to sam1 offset fraction
	addx.l	d2,d5			add sam1 inc int to sam1 offset int (lower) &
*					add sam2 inc frac to sam2 offset frac (upper)
	addx.w	d3,d6			add sam2 inc int to sam2 offset int
	ENDM
I did it in a fairly crappy brute force way to start with, just to make sure it works as intended and now I'm trying to optimise it a bit :) Worst case scenario however it's still fast enough to buffer 6 channels with full resolution and volume control at 12.5KHz, which with full sample resolution sounds pretty good to me. Hopefully I can also get it fast enough to do 4 channels at 25KHz.
UNSEEN MENACE
2 original ST's, several STFM's, 2 STE's, a TT and a 14MB Falcon,
a Lynx 2 and Jaguar with JagCD
User avatar
leonard
Moderator
Moderator
Posts: 683
Joined: Thu May 23, 2002 10:48 pm

Re: Help with sample mixing routine please

Post by leonard »

unseenmenace wrote: Tue Oct 26, 2021 7:55 am Assuming that only works with a7 and not other address registers that might be difficult to take advantage of if I need interrupts to be able to happen right?
You can use the .b (a7)+ and also use interrupts. Just remind 68k has two a7 registers : user and supervisor stack. I'm using that in my AmigaPaulaEmulator: right before your mixing code, go to user mode move.w #$300,sr. Do your mixing code with a7 pointing on your sample buffer ( interrupts could occur because it will use supervisor stack pointer). At the end of your mixing, you can go back to supervisor using trap #0 for instance.

myTrap0: ori.w #$2000,(a7) ; set supervisor bit for following rte
rte
Leonard/OXYGENE.
User avatar
thomas3
Captain Atari
Captain Atari
Posts: 400
Joined: Tue Apr 11, 2017 8:57 pm

Re: Help with sample mixing routine please

Post by thomas3 »

leonard wrote: Wed May 18, 2022 12:01 am You can use the .b (a7)+ and also use interrupts. Just remind 68k has two a7 registers : user and supervisor stack. I'm using that in my AmigaPaulaEmulator: right before your mixing code, go to user mode move.w #$300,sr. Do your mixing code with a7 pointing on your sample buffer ( interrupts could occur because it will use supervisor stack pointer). At the end of your mixing, you can go back to supervisor using trap #0 for instance.

myTrap0: ori.w #$2000,(a7) ; set supervisor bit for following rte
rte
NICE! Now THAT'S what I call a pro-tip :)

But - surely you run into problems if your interrupt code requires supervisor mode, unless you switch to supervisor and back each interrupt? Simple example: writing straight to colour registers?
User avatar
Dbug
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 105
Joined: Tue Jan 28, 2003 8:42 pm
Location: Oslo (Norway)

Re: Help with sample mixing routine please

Post by Dbug »

thomas3 wrote: Wed May 18, 2022 9:14 am
leonard wrote: Wed May 18, 2022 12:01 am You can use the .b (a7)+ and also use interrupts. Just remind 68k has two a7 registers : user and supervisor stack. I'm using that in my AmigaPaulaEmulator: right before your mixing code, go to user mode move.w #$300,sr. Do your mixing code with a7 pointing on your sample buffer ( interrupts could occur because it will use supervisor stack pointer). At the end of your mixing, you can go back to supervisor using trap #0 for instance.

myTrap0: ori.w #$2000,(a7) ; set supervisor bit for following rte
rte
NICE! Now THAT'S what I call a pro-tip :)

But - surely you run into problems if your interrupt code requires supervisor mode, unless you switch to supervisor and back each interrupt? Simple example: writing straight to colour registers?
Imo, you perform Leonard's trick if you don't care about stability, like you have a long bunch of mixing to do and you want to enable the mouse and keyboard IRQ for example.

In the case of writing to color registers, you would like to be somewhat synchronized with the proper position on screen, so either you would not use that trick, or you would do the color changes using either the HBL or Timer B to change the colors at the proper location.
User avatar
thomas3
Captain Atari
Captain Atari
Posts: 400
Joined: Tue Apr 11, 2017 8:57 pm

Re: Help with sample mixing routine please

Post by thomas3 »

Yeah, what I mean is, surely if an interrupt (timer B whatever) executes during the mixer code, it'll be run under user mode?
User avatar
Dbug
Obsessive compulsive Atari behavior
Obsessive compulsive Atari behavior
Posts: 105
Joined: Tue Jan 28, 2003 8:42 pm
Location: Oslo (Norway)

Re: Help with sample mixing routine please

Post by Dbug »

Interrupts always run in supervisor mode, so that's not a problem :)
You can totally switch to supervisor to install an exception handler and then go back to user mode.
User avatar
thomas3
Captain Atari
Captain Atari
Posts: 400
Joined: Tue Apr 11, 2017 8:57 pm

Re: Help with sample mixing routine please

Post by thomas3 »

Dbug wrote: Wed May 18, 2022 10:37 am Interrupts always run in supervisor mode, so that's not a problem :)
You can totally switch to supervisor to install an exception handler and then go back to user mode.
I didn't know this. Neat! Thanks!
User avatar
Grazey / PHF
Atari Super Hero
Atari Super Hero
Posts: 571
Joined: Fri Jun 21, 2002 12:50 pm
Location: Montreal, Quebec

Re: Help with sample mixing routine please

Post by Grazey / PHF »

leonard wrote: Wed May 18, 2022 12:01 am You can use the .b (a7)+ and also use interrupts. Just remind 68k has two a7 registers : user and supervisor stack. I'm using that in my AmigaPaulaEmulator: right before your mixing code, go to user mode move.w #$300,sr. Do your mixing code with a7 pointing on your sample buffer ( interrupts could occur because it will use supervisor stack pointer). At the end of your mixing, you can go back to supervisor using trap #0 for instance.

myTrap0: ori.w #$2000,(a7) ; set supervisor bit for following rte
rte
That's exactly what Jurgen Piscol does in his Soundmachine (c) 1990 routine - used in games such as Oxyd.

Here's my disassembly :)

Image

Saying that, it's still in my WIP folder as I'm struggling to get it running with the OS.

Grazey
http://phf.atari.org - demo coders since 1983
http://sndh.atari.org - Maintainer of the Atari ST chip music archive
http://www.scenestream.net - Nectarine Administrator

Return to “The Digital Department”