|
Acorn Arcade forums: Programming: Sound DMA / emulating IOC device 9
|
Sound DMA / emulating IOC device 9 |
|
sirbod (05:56 3/7/2014) Phlamethrower (12:53 3/7/2014) sirbod (22:19 5/7/2014) Phlamethrower (02:18 6/7/2014) sirbod (05:37 6/7/2014) qUE (11:38 6/7/2014) sirbod (11:49 6/7/2014) Phlamethrower (12:21 6/7/2014) sirbod (12:31 6/7/2014) qUE (17:57 6/7/2014) sirbod (20:59 6/7/2014) sirbod (13:09 9/7/2014) Phlamethrower (14:33 9/7/2014) sirbod (16:10 9/7/2014) sirbod (16:53 9/7/2014) arawnsley (10:26 10/7/2014) sirbod (19:03 10/7/2014) sirbod (19:16 10/7/2014) sirbod (19:36 14/7/2014) Phlamethrower (22:01 14/7/2014) sirbod (06:55 19/7/2014) Phlamethrower (13:16 21/7/2014) sirbod (17:36 21/7/2014) Phlamethrower (22:28 21/7/2014) sirbod (17:50 24/7/2014) sirbod (22:40 26/7/2014)
|
|
Jon Abbott |
Message #123266, posted by sirbod at 05:56, 3/7/2014 |
Member
Posts: 563
|
What happens when SDENDA / SDENDB (Sound buffer A/B end) are hit on IOMD?
Does it raise an IRQ, leaving the IRQ handler to query SDST I/W bits (Sound DMA status) to determine if and which Sound buffer is exhaust?
I've read the ARM7500 manual sound sections several times, but can't see anything that describes buffer exhaustion. |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123267, posted by Phlamethrower at 12:53, 3/7/2014, in reply to message #123266 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
Does it raise an IRQ, leaving the IRQ handler to query SDST I/W bits (Sound DMA status) to determine if and which Sound buffer is exhaust? That looks to be the case, judging by the way the IOMD version of SoundDMA is implemented.
https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/HWSupport/Sound/Sound0/s/Sound0?rev=4.18#l2877 |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123272, posted by sirbod at 22:19, 5/7/2014, in reply to message #123267 |
Member
Posts: 563
|
It raises an IRQ for device 20, which appears to work identically to device 9 on IOC.
The only difference between IOC/IOMD seems to be that SDENDA/B are offsets in the page, so sound can't wrap onto the next physical memory page and SDSTARTA/B must be written first.
The write order is identical to IOC, however some games don't comply with the docs, Rockfall for example writes Sstart before SendN.
One problem I do have to solve is translating the IOC physical address written to Sstart/SendN to an IOMD physical address. Both Diggers and Rockfall have hardcoded physical addresses, which would require prior knowledge of the ARM2 memory map to translate.
If RO3.1 maps pages in a certain order, provided I know the order I could translate the pages. I know DA2 is mapped first, I'm guessing the cursor/sound buffer area is next, I'm not sure what the order is after that though. |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123273, posted by Phlamethrower at 02:18, 6/7/2014, in reply to message #123272 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
It looks like RO 3.1 uses a fixed physical address for the sound & cursor buffers - somewhere within the last 32K of the 512K of DMA'able RAM. I.e. deliberately located outside of the 480K that's usable by DA 2, so that the OS doesn't have to worry about remapping it when the screen DA grows.
Older OS versions would have used fixed addresses as well, although you'd probably have to check each version individually just in case the addresses have shifted a bit. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123274, posted by sirbod at 05:37, 6/7/2014, in reply to message #123273 |
Member
Posts: 563
|
The physical page mappings from looking at the MEMC table are:
0: DA2 ... E: 1F00000 Cursor / Sound Buffers F: 0
It looks like the Sound buffers are always mapped to the same page, regardless of what other memory sliders are at.
[Edited by sirbod at 09:04, 6/7/2014]
Outside of the WIMP, free pages after DA2 and before the Sound buffers are mapped to:
1800000 Heap 8000 and up
When the WIMP is running, this doesn't work however but Rockfall seems to still produce sound okay even with a hardcoded physical address of 14000-16000
[Edited by sirbod at 10:56, 6/7/2014] |
|
[ Log in to reply ] |
|
qUE |
Message #123275, posted by qUE at 11:38, 6/7/2014, in reply to message #123274 |
Posts: 187
|
Don't forget MEMC Logical and Physical memory are different ranges.
Like JL said, the Sound Buffers are within the first 512K of Physical Memory because that's what the VIDC registers allow (upper bits used for what index of register you're referring to)
How you the map that Physical memory space to Logical with the MEMC is up to you.
In answer to the original question, from what I know from the IOC, the VIDC sound pointer self increments until it hits what you've marked as end, it'll then raise an IRQ, your IRQ routine then should either advanced the end pointer (to say carry on play next chunk of the sound) or reset the start pointer (to replay or play new samples you've updated).
Hope that's not too confusing, it's been a few years since I've done those routines.
qUE |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123276, posted by sirbod at 11:49, 6/7/2014, in reply to message #123275 |
Member
Posts: 563
|
Don't forget MEMC Logical and Physical memory are different ranges.
Like JL said, the Sound Buffers are within the first 512K of Physical Memory because that's what the VIDC registers allow (upper bits used for what index of register you're referring to) It's all coded and working to a certain degree*, I just need to work out how to translate the hardcoded physical addresses games+ are using back to logical, so I can then translate back to IOMD physical for the IOMD registers.
Physical 7E000 / 7F000 map to 1F06000 / 1F07000 - that's easy enough as its a fixed physical page. The problems I'm having are with games that use application space to write their sound buffers. To translate them, I need prior knowledge of the RO3.1 physical memory map...hence the tables in the post above.
I've tried passing through the physical address, which doesn't work, so IOMD physical page mappings don't match the IOC ones.
* Diggers music plays on IOMD + No Excuses, Rockfall, Gribbly's Day Out
EDIT: Subtracting DA2 looks like it's sufficient to work out the logical address, I'm getting sound effects in No Excuses and Rockfall now.
[Edited by sirbod at 13:27, 6/7/2014] |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123277, posted by Phlamethrower at 12:21, 6/7/2014, in reply to message #123276 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
Hmm - so you've got games which aren't using physical addresses &7e000/&7f000, and are instead using hardcoded physical addresses that map to application space? I'm surprised that even works, I would have thought the logical/physical mapping of application space would be too unpredictable for it to be possible to hardcode the addresses.
Are you sure they aren't using OS_ReadMemMapEntries/OS_FindMemMapEntries to work out the physical address? E.g.:- Call OS_FindMemMapEntries to get the page number
- Multiply page number by page size (from OS_ReadMemMapInfo)
- Write that address to VIDC
That means you should be able to do the reverse in order to get back to a physical page number, and then use OS_Memory to translate that to a physical address. However there's a strong chance that on RO 3.5+ the pages they're using won't be in the first 512K of physical RAM, so they'll end up either corrupting the address they write to VIDC or botching the write altogether by writing to a completely different register/address. In which case I'd say your best solution would be to patch the game code directly. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123278, posted by sirbod at 12:31, 6/7/2014, in reply to message #123277 |
Member
Posts: 563
|
Are you sure they aren't using OS_ReadMemMapEntries/OS_FindMemMapEntries to work out the physical address? Nope, hardcoded entries in the game code. We're talking about games written for Arthur in the most, although Diggers is a fine example of how not to code a game in 1994! They hardcoded 7E000/7F000 into it.
It actually looks fairly predicable on RO3.1, as per my edit above, simply subtracting DA2 size seems to result in the correct logical address - provided the game is smaller than 512k |
|
[ Log in to reply ] |
|
qUE |
Message #123279, posted by qUE at 17:57, 6/7/2014, in reply to message #123278 |
Posts: 187
|
jon, you sure it's not just directly accessing the physical memory range which is perfectly allowed and theoretically quick since you're avoiding logical translation look up.
would be something like &2007E000
qUE |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123280, posted by sirbod at 20:59, 6/7/2014, in reply to message #123279 |
Member
Posts: 563
|
jon, you sure it's not just directly accessing the physical memory range which is perfectly allowed and theoretically quick since you're avoiding logical translation look up.
would be something like &2007E000 I was referring to the value Diggers writes to MEMC Sstart; it's hardcoded to the RO3.1 physical address for the sound buffers.
As as aside, two of the games I've been looking at today have bugs in the DMA set code. No Excuses tries to set MEMC DMA register 7, which doesn't exist and Rockfall writes Sstart and SendN in the wrong order. I'm fixing No Excuse at runtime and did initially fix Rockfall in the same way, in the end however I changed my code to track the MEMC registers and only write the IOMD equivelants when both MEMC registers were available, to get around the change in register write order between MEMC and IOMD.
Diggers had a compiler bug, where at least one function call jumps to the function address-4, I'm expecting to find more once I get the main game code running. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123282, posted by sirbod at 13:09, 9/7/2014, in reply to message #123266 |
Member
Posts: 563
|
This is all coded now and appears to work ok on VIDC20, the next issue is converting 8bit ulaw to 16bit linear.
SoundDMA compiles code for this in the RMA when its initialised, is it exposed so it can be called or triggered to do the conversion? That will save me creating my own routine and will ensure future compatibility, provided SoundDMA retains support for 8bit sound.
Is there a reason why SoundDMA doesn't register this code as the system default Linear Handler so it can be called?
[Edited by sirbod at 14:10, 9/7/2014] |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123283, posted by Phlamethrower at 14:33, 9/7/2014, in reply to message #123282 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
SoundDMA compiles code for this in the RMA when its initialised, is it exposed so it can be called or triggered to do the conversion? Nope.
Is there a reason why SoundDMA doesn't register this code as the system default Linear Handler so it can be called? No idea. But that wouldn't solve your problem - you'd still need a separate interface to be available for calling the conversion code with the right parameters (buffer pointers, channel count, stereo positions, etc.)
What happens when a game configures the sound system? (Whether via SWIs or direct hardware access). Are you intercepting that all in order to provide a full emulation of the Arc sound system, or are you relying on the host machine to support all the different sample rates, etc.?
If you're just passing the configuration changes through to the OS then you should probably just copy the contents of the games sound buffer into the OS's sound buffer whenever the game finishes filling its buffer. That way SoundDMA will convert the samples for you as part of its regular operation. If necessary you can replace/intercept the channel handler that's set by Sound_Configure, so that you can use that as your trigger to copy the contents of the game's sound buffer. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123284, posted by sirbod at 16:10, 9/7/2014, in reply to message #123283 |
Member
Posts: 563
|
No idea. But that wouldn't solve your problem - you'd still need a separate interface to be available for calling the conversion code with the right parameters (buffer pointers, channel count, stereo positions, etc.) On IOMD I'm leaving RO to handle Sound_Configure etc as it's all backward compatible, so SoundDMA already knows all the parameters. The only bit that's missing is to get SoundDMA to do the conversion at the correct point in time.
What happens when a game configures the sound system? (Whether via SWIs or direct hardware access). Are you intercepting that all in order to provide a full emulation of the Arc sound system, or are you relying on the host machine to support all the different sample rates, etc.? Relying on the host machine for IOMD.
If you're just passing the configuration changes through to the OS then you should probably just copy the contents of the games sound buffer into the OS's sound buffer whenever the game finishes filling its buffer. The game in question (Diggers) is already writing to the OS sound buffer, the problem is that SoundDMA isn't kicking in until VIDC has already part played the buffer. I suppose I could try ignoring the MEMC write if it's setting the buffer to the OS default and see if SoundDMA converts it correctly.
As there's no way to trigger the SoundDMA linear handler, I'll have to code one for newer machines. A bit annoying considering SoundDMA already has it built in. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123285, posted by sirbod at 16:53, 9/7/2014, in reply to message #123284 |
Member
Posts: 563
|
I suppose I could try ignoring the MEMC write if it's setting the buffer to the OS default and see if SoundDMA converts it correctly. Unfortunately this doesn't work, as the IRQ's to fill the buffer aren't being raised by IOMD. I though SoundDMA was always filling the buffer even if no sound is being generated, this doesn't seem to be the case though*.
My only option is to unplug SoundDMA and take over it's function with my own linear handler that I call when I see the MEMC write to set the sound DMA.
I might try botching it first though, it looks like SoundDMA writes its handler to the start of its RMA allocation, so I'll try calling it directly.
EDIT: *Thinking about it, this wouldn't work anyway as the game is taking over the device. I'd have to pass the device IRQ onto SoundDMA.
[Edited by sirbod at 18:05, 9/7/2014] |
|
[ Log in to reply ] |
|
Andrew Rawnsley |
Message #123286, posted by arawnsley at 10:26, 10/7/2014, in reply to message #123285 |
R-Comp chap
Posts: 600
|
Jon, is it absolutely necessary to unplug things rather than RMkill etc?
I've had a couple of cases our customers have tried recent versions of ADFFS on RISC OS 5, then had crashes, and been left with unbootable machines (ie. won't get to desktop) because key modules have been unplugged.
This may be down to user error, of course, but equally unbootable machine is never good |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123287, posted by sirbod at 19:03, 10/7/2014, in reply to message #123286 |
Member
Posts: 563
|
Jon, is it absolutely necessary to unplug things rather than RMkill etc? I meant to say RMKill ... ADFFS doesn't kill or unplug any modules, with the exception of ADFS which is re-initialised and BASIC with is also re-initialised on StrongARM up, so ADFFS can hook into CALL and USR.
I've had a couple of cases our customers have tried recent versions of ADFFS on RISC OS 5, then had crashes, and been left with unbootable machines (ie. won't get to desktop) because key modules have been unplugged.
This may be down to user error, of course, but equally unbootable machine is never good Sorry to hear that, they should have brought it to my attention.
Provided the game has been released by the project, is confirmed as working on RO5 (it says on the download page), SparkFS is loaded and the game is run via "Boot floppy" - no modules or CMOS changes will be made by the game, ADFFS will prevent it.
If it's becoming a problem, I could prevent read access to the floppies to prevent people from trying to run the game directly - that's when you'll see nasty things happening as back in the day, it seems it was acceptable for a game to completely trash the CMOS.
EDIT: I've changed the wording on the instructions next to the ADFFS download link to specifically point out that damage will occur if the instructions aren't followed:
You must have !SparkFS loaded and use "Boot floppy" to run a game. If you don't, you could end up with a machine that isn't bootable, as some games try to alter the CMOS. Provided "Boot floppy" is used, ADFFS will prevent games from altering both the CMOS and unplugging modules. DO NOT try to run a game by launching it's Icon - it will almost certainly damage your machine.
[Edited by sirbod at 20:25, 10/7/2014] |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123288, posted by sirbod at 19:16, 10/7/2014, in reply to message #123285 |
Member
Posts: 563
|
Thinking about it, this wouldn't work anyway as the game is taking over the device. I'd have to pass the device IRQ onto SoundDMA. Is it possible to get the previous owner of a device, so I can pass the IRQ onto SoundDMA once the game has filled the sound buffer?
On this thread, does SoundDMA on the Pi, BB etc still support conversion of 8bit to whatever the native hardware supports or has 8bit been dropped? |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123293, posted by sirbod at 19:36, 14/7/2014, in reply to message #123282 |
Member
Posts: 563
|
This is all coded now and appears to work ok on VIDC20, the next issue is converting 8bit ulaw to 16bit linear.
SoundDMA compiles code for this in the RMA when its initialised, is it exposed so it can be called or triggered to do the conversion? That will save me creating my own routine and will ensure future compatibility, provided SoundDMA retains support for 8bit sound.
Is there a reason why SoundDMA doesn't register this code as the system default Linear Handler so it can be called? On further investigation it turns out that SoundDMA is working at the correct time, the issue is that if SoundSystem is configured for 16bit sound, SoundDMA is not compiling an 8bit conversion routine. If I reconfigure SoundSystem to 8bit, RMReInit SoundDMA and then let Diggers run with ADFFS translating the MEMC writes, the music is correct.
So, the problem I'm facing on RO3.71 is dynamically switching SoundDMA to 8bit code for legacy games. Looking at the SoundDMA code, I can't see any way to do this, short of modifying the CMOS.
On RO5, I need to take over the whole sound stack under the JIT and implement SharedSound code to do the translation. I'll probably do this for all sound with a RO3.1/3.71 SoundDMA module loaded in the JIT Module space for compatibility. The only problem I need to figure out is how to emulate IOC device 6 or IOMD device 20 at the correct rate. It will have to be IRQ driven to ensure the game speed is correct and pretty accurate to avoid sound glitches. |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123294, posted by Phlamethrower at 22:01, 14/7/2014, in reply to message #123293 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
On further investigation it turns out that SoundDMA is working at the correct time, the issue is that if SoundSystem is configured for 16bit sound, SoundDMA is not compiling an 8bit conversion routine. If I reconfigure SoundSystem to 8bit, RMReInit SoundDMA and then let Diggers run with ADFFS translating the MEMC writes, the music is correct. Surely that's backwards?
If 16bit sound is configured, all sound output is 16bit, therefore the 8bit to 16bit conversion routine is used.
If 8bit output is configured, all sound output is 8bit, therefore no conversion is required. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123296, posted by sirbod at 06:55, 19/7/2014, in reply to message #123294 |
Member
Posts: 563
|
Surely that's backwards? I seem to have swapped all references to 8bit/16bit!
Although it works for Diggers, it doesn't work for No Excuses* or Rockfall*, so it's back to the drawing board. I need to come up with a solution that works for RO3.5+ and all sound hardware from VIDC20 onward.
My thoughts at the moment are to obviscate the game's sound from the physical and essentially emulate VIDC/MEMC into a circular 8bit mu-law buffer which is then converted via SharedSound to the actual sound buffer.
To implement, I believe I need to do the following:
1. Track MEMC Sound DMA registers, copying the sound buffer to an internal 8bit circular buffer, when both Sstart and SendN are set 2. Track VIDC Sound registers 3. Take over OS_InstallDeviceDriver for device 9 4. Generate an emulated IOC device 9 IRQ at the rate MEMC would, which calls both the emulated IRQ vector and any registered device 9 code 5. Install a SharedSound handler which converts the 8bit sound to 16bit and handles the frequency difference between the game and the hardware 6. Take over Sound_Configure so calls aren't passed to the OS, simply track the parameters for use by the SharedSound handler
This raises several issues: 1. How to generate the emulated IOC device 9 IRQ at the correct rate 2. Knowing when to take over Sound_Configure or pass it through to the OS 3. Possible lag in audio vs screen, the audio will be at least one buffer behind as a min of two buffers worth will be required to ensure there's enough to fill the physical audio buffer 4. What to do about SoundDMA, should I emulate the RO3.1 module in its entirety? Or, leave the current one.
* No Excuses uses one-shot Sstart/SendN values that are larger than the stock RO3.5 sound buffer. On IOC the DMA buffer length can be 512kb long
* Rockfall also uses one-shot Sstart/SendN values, but these are a max of &A30 in length
[Edited by sirbod at 13:21, 21/7/2014] |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123299, posted by Phlamethrower at 13:16, 21/7/2014, in reply to message #123296 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
Yeah, providing your own full emulation of the Arc sound system sounds like your only real option. Otherwise you'd just run into too many issues with games expecting certain DMA buffer sizes, buffer fill rates, etc.
1. How to generate the emulated IOC device 9 IRQ at the correct rate You'd almost certainly need to use a timer interrupt (HAL timer/IOC timer 1).
4. What to do about SoundDMA, should I emulate the RO3.1 module in its entirety? Or, leave the current one. In order to catch configuration changes being made by games I think you'd have to emulate the module in its entirety. But as you say I think that will introduce problems with trying to work out when to intercept or when to pass through.
Regarding when to process the sound - rather than process a full buffer's worth of data in one go, ArcEm goes down the route of processing it in batches, using the following basic algorithm:
1. Read N 16 byte DMA chunks of mu-law source data 2. Convert each DMA chunk to 16 stereo sample pairs (no channel mixing yet) 3. Store in an intermediate buffer 4. Swap DMA buffers and raise IRQ as necessary 5. If there are enough samples in the intermediate buffer, perform sample rate conversion and channel mixing, feeding the output to the OS-specific sound code 6. OS-specific sound code then either sends it straight through or (for the case of RISC OS) adds it to a buffer which is then read from by the SharedSound handler
There's a timer set up which triggers the whole process at the correct rate for whatever the emulated sound frequency should be. E.g. for 4-channel sound at 20833Hz with the routine processing one DMA chunk per tick, that would be a 5208Hz timer (20833*4/(16*1)). However for the RISC OS version of ArcEm it looks like I've set the batch size to 256 DMA chunks (20Hz), which will have the net effect of making it process the entire DMA buffer in one go (at least assuming a standard 100Hz buffer fill rate). So maybe don't pay so much attention to this discussion about batching (although it will obviously help for extreme cases like 512KB DMA buffers)
Then there's the second point you've probably noticed, which is that the channel mixing is deferred until the sample rate conversion is performed. This is because, just by reading the hardware registers, there's no way of determining how many audio channels are being used. You can kind of guess by looking at the settings of the stereo position registers, but that will fall apart when you come across a game which uses multiple channels but only mono sound (Lotus II, IIRC), or regularly changes the stereo position of sounds (Asylum, IIRC). So for ArcEm (and potentially ADFFS) the only real way of doing things was to provide an emulation of the time division multiplexing-like method in which the Arc provided multichannel sound in the first place - there's only one ADC which just runs through a continuous serial stream of samples, and then there's a bit of extra circuitry afterwards which runs in sync with the ADC to apply the stereo bias. And presumably some filters in there to smooth the output a bit.
It's probably worth taking a look at the mixing code in the ArcEm sources to (hopefully) get a better idea of what I'm talking about here. The algorithm there is actually a C translation of some original code that was written in NEON, although I'm yet to find the time to hook the NEON version up to ArcEm (the C version is a bit of a CPU hog due to it needing to read in 8+ samples in order to produce a single output sample). Also note that it only uses point sampling, although I think it wouldn't be too hard to hook up Lanczos or something else instead (e.g. apply the Lanczos function to each source sample, with the 8x duration modifier), including a NEON-optimised version. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123300, posted by sirbod at 17:36, 21/7/2014, in reply to message #123299 |
Member
Posts: 563
|
You'd almost certainly need to use a timer interrupt (HAL timer/IOC timer 1). I tried using HAL timer on the Pi previously and had all sorts of issues with stack corruption when swapping CPU modes - I gave up in the end. I'm dreading trying to use them for audio! I'd rather avoid them until there's a proper interface for them, talking directly to the HAL isn't good for future compatibility.
IOC timer 1 isn't an option on IOMD as most games will be using it already. I'll probably need to split the code, so IOMD is handled differently. With IOMD I can either upsample/16bit the audio when the MEMC registers are written, or force IOMD to 8bit to avoid upsampling/16bit. To get Diggers/No Excuses/Rockfall working on RO3.5, ADFFS does the following when Sstart/SendN are both set:
If Sound_Mode = 16bit then Call SoundDMA compiled code (convert from game buffer to 16bit in the SoundDMA buffer) If Sound_Mode = Oversample then Upsample Write the IOMD Sstart/SendN equivelent registers
For DMA buffer sizes >SoundDMA buffer size, my current thinking is to direct device 20 to ADFFS first, which checks to see if the previous DMA buffer size was >SoundDMA buffer size, if it was, it handles one SoundDMA buffer's worth of audio and increases the DMA address until it reaches SendN. Only then does it pass the IRQ's to the game.
4. What to do about SoundDMA, should I emulate the RO3.1 module in its entirety? Or, leave the current one. In order to catch configuration changes being made by games I think you'd have to emulate the module in its entirety. But as you say I think that will introduce problems with trying to work out when to intercept or when to pass through. An option here is to force such games to run under the JIT so we know what should go to the system and what needs emulating. This is how I'm testing currently on IOMD, so I'd just need to redirect all the SoundDMA SWI's to my own code - or run the original SoundDMA module under the JIT
Regarding when to process the sound - rather than process a full buffer's worth of data in one go, ArcEm goes down the route of processing it in batches For IOMD, I can process one "system sound buffer size" worth of data at a time combined with the method above to handle DMA buffer sizes that are too big.
Eveything else will need an intermediately buffer, processing one buffer (game or system size, whichever is the smaller) worth of audio until there's enough audio to interpolated and play via a SharedSound handler.
Then there's the second point you've probably noticed, which is that the channel mixing is deferred until the sample rate conversion is performed. This is because, just by reading the hardware registers, there's no way of determining how many audio channels are being used. You can kind of guess by looking at the settings of the stereo position registers, but that will fall apart when you come across a game which uses multiple channels but only mono sound (Lotus II, IIRC), or regularly changes the stereo position of sounds (Asylum, IIRC). So for ArcEm (and potentially ADFFS) the only real way of doing things was to provide an emulation of the time division multiplexing-like method I don't think I'll have this problem as I can intercept Sound_Configure and already track the VIDC registers, so know exactly how many channels are set.
It's probably worth taking a look at the mixing code in the ArcEm sources to (hopefully) get a better idea of what I'm talking about here. I did take a look last week to see how SharedSound worked - I've since made a start on adding SharedSound documentation to the Wiki based on the ROOL source code |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #123301, posted by Phlamethrower at 22:28, 21/7/2014, in reply to message #123300 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
I did take a look last week to see how SharedSound worked - I've since made a start on adding SharedSound documentation to the Wiki based on the ROOL source code The OS SWIs StrongHelp manual has a section on SharedSound - that's what I've used as reference for all my code that uses it. However there are quite a few SWIs/features marked as unimplemented, so it's probably best to double-check the source to see what does and doesn't work. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123303, posted by sirbod at 17:50, 24/7/2014, in reply to message #123296 |
Member
Posts: 563
|
* No Excuses uses one-shot Sstart/SendN values that are larger than the stock RO3.5 sound buffer. On IOC the DMA buffer length can be 512kb long
* Rockfall also uses one-shot Sstart/SendN values, but these are a max of &A30 in length To handle these cases, I need to take over device 20 on IOMD as soon as the JIT starts up. That then adds the problem of how to pass the IRQ onto SoundDMA if we're not dealing with any sound.
It doesn't look like it's legally possible to find out the previous owner of a device, or pass a call onto the previous device handler. Any ideas on how I can pass IRQ's onto SoundDMA?
My plan is to sit between the game and SoundDMA passing one buffer worth of data on each IRQ to SoundDMA, increasing Sptr (emulated) until SendN (emulated) is reached, at which point all IRQ's are passed onto SoundDMA until Sstart/SendN are set again. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #123304, posted by sirbod at 22:40, 26/7/2014, in reply to message #123303 |
Member
Posts: 563
|
Now that I've looked through the RISCOS source code for layer 0 / 1 audio, it looks like one option is to sit between SoundDMA and SoundChannels.
EDIT: I've moved this to the JASPP forum as its now rather specific to ADFFS
[Edited by sirbod at 12:04, 27/7/2014] |
|
[ Log in to reply ] |
|
|
Acorn Arcade forums: Programming: Sound DMA / emulating IOC device 9 | |
|