31 March 2024, 19:20 | #1 |
old chunk of coal
Join Date: Nov 2011
Location: Hungary
Posts: 1,318
|
Noise after playing a sound with audio.device
I'd like to start non-looping sounds asynchronously both on a left and right channel using audio.device. I dusted off some old code I used in other projects, but there's a problem with clicks and pops after some sound effects.
It works by creating separate audio requests for the left and right channel, and uses the original request for control commands only. I apologize if this isn't the right forum section, but since the example code is in C I thought it should fit here. Code:
#include <graphics/gfxbase.h> #include <devices/audio.h> #include <proto/exec.h> #include <proto/dos.h> #include <proto/graphics.h> #include <clib/alib_protos.h> enum { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_COUNT }; #define LEFT_MASK 0x9 #define RIGHT_MASK 0x6 typedef struct { struct MsgPort *port; struct IOAudio *ioreq; BYTE device; } audiodev_t; static BOOL audiodev_init(audiodev_t *dev, UBYTE *whichannel, ULONG chancount) { if ((dev->port = CreateMsgPort())) { if ((dev->ioreq = (struct IOAudio *)CreateIORequest(dev->port, sizeof(struct IOAudio)))) { struct IOAudio *audioReq = dev->ioreq; audioReq->ioa_Request.io_Message.mn_Node.ln_Pri = 127; // no stealing audioReq->ioa_Request.io_Command = ADCMD_ALLOCATE; audioReq->ioa_Request.io_Flags = ADIOF_NOWAIT; audioReq->ioa_AllocKey = 0; audioReq->ioa_Data = whichannel; audioReq->ioa_Length = chancount; if (!(dev->device = OpenDevice((STRPTR)AUDIONAME, 0, (struct IORequest *)audioReq, 0))) { return TRUE; } } } return FALSE; } static void audiodev_close(audiodev_t *dev) { if (!dev->device) { struct IOAudio *audioReq = dev->ioreq; audioReq->ioa_Request.io_Command = CMD_RESET; audioReq->ioa_Request.io_Flags = 0; DoIO((struct IORequest *)audioReq); CloseDevice((struct IORequest *)audioReq); dev->device = -1; } if (dev->ioreq) { DeleteIORequest((struct IORequest *)dev->ioreq); dev->ioreq = NULL; } if (dev->port) { DeleteMsgPort(dev->port); dev->port = NULL; } } static audiodev_t digidev; static struct IOAudio digiChannelReq[CHANNEL_COUNT]; static LONG audioClock; static UWORD audioPeriod; static void channel_init(struct IOAudio *srcio, struct IOAudio *destio, ULONG chanmask) { CopyMem(srcio, destio, sizeof(struct IOAudio)); destio->ioa_Request.io_Unit = (struct Unit *)((ULONG)destio->ioa_Request.io_Unit & chanmask); destio->ioa_Request.io_Message.mn_ReplyPort = CreateMsgPort(); destio->ioa_Request.io_Message.mn_Node.ln_Type = 0; destio->ioa_Length = 0; destio->ioa_Request.io_Command = CMD_WRITE; } static void channel_close(struct IOAudio *destio) { destio->ioa_Request.io_Command = CMD_FLUSH; destio->ioa_Request.io_Flags = 0; DoIO((struct IORequest *)destio); if (destio->ioa_Request.io_Message.mn_ReplyPort) { DeleteMsgPort(destio->ioa_Request.io_Message.mn_ReplyPort); destio->ioa_Request.io_Message.mn_ReplyPort = NULL; } } int sound_init(int rate) { UBYTE whichannel[] = {3, 5, 10, 12}; if (audiodev_init(&digidev, whichannel, sizeof(whichannel))) { channel_init(digidev.ioreq, &digiChannelReq[CHANNEL_LEFT], LEFT_MASK); channel_init(digidev.ioreq, &digiChannelReq[CHANNEL_RIGHT], RIGHT_MASK); if (GfxBase->DisplayFlags & PAL) audioClock = 3546895; else audioClock = 3579545; audioPeriod = audioClock / rate; return 1; } audiodev_close(&digidev); return 0; } void sound_close(void) { channel_close(&digiChannelReq[CHANNEL_LEFT]); channel_close(&digiChannelReq[CHANNEL_RIGHT]); audiodev_close(&digidev); } static void channel_setup(struct IOAudio *audioio, UBYTE *data, ULONG length, UWORD period, UWORD volume, UWORD cycles) { audioio->ioa_Data = data; audioio->ioa_Length = length; audioio->ioa_Period = period; audioio->ioa_Volume = volume; audioio->ioa_Cycles = cycles; audioio->ioa_Request.io_Flags = ADIOF_PERVOL; } void sound_stop(void) { struct IOAudio *audioReq = digidev.ioreq; audioReq->ioa_Request.io_Command = CMD_FLUSH; DoIO((struct IORequest *)audioReq); } void sound_play(char *data, int length, int rate, int leftvol, int rightvol, int cycles) { struct IOAudio *audioReq = digidev.ioreq; struct IOAudio *digiLeftReq = &digiChannelReq[CHANNEL_LEFT]; struct IOAudio *digiRightReq = &digiChannelReq[CHANNEL_RIGHT]; GetMsg(digiLeftReq->ioa_Request.io_Message.mn_ReplyPort); GetMsg(digiRightReq->ioa_Request.io_Message.mn_ReplyPort); audioReq->ioa_Request.io_Command = CMD_STOP; DoIO((struct IORequest *)audioReq); channel_setup(digiLeftReq, data, length, audioPeriod, leftvol, cycles); channel_setup(digiRightReq, data, length, audioPeriod, rightvol, cycles); BeginIO((struct IORequest *)digiLeftReq); BeginIO((struct IORequest *)digiRightReq); audioReq->ioa_Request.io_Command = CMD_START; DoIO((struct IORequest *)audioReq); } #include "sound19.h" int main(int argc, char *argv[]) { if (!sound_init(8000)) return 1; Printf("Playing the sound...\n"); sound_play(sound19_au, sound19_au_len, 0, 64, 64, 1); Printf("Waiting for 10 seconds...\n"); Delay(10*50); sound_close(); return 0; } I'm attaching the the problematic sound, so the code can be built with gcc: Code:
m68k-amigaos-gcc -o sndtest audiodev.c -noixemul |
31 March 2024, 19:36 | #2 |
Registered User
Join Date: Jun 2016
Location: europe
Posts: 1,097
|
This works fine for me as is, and also after changing it to loop with 1sec delay.
Are the lengths correct? I'd use this instead, e.g. Code:
// unsigned int sound19_au_len = 3040; unsigned int sound19_au_len = sizeof(sound19_au); |
31 March 2024, 19:59 | #3 |
old chunk of coal
Join Date: Nov 2011
Location: Hungary
Posts: 1,318
|
The length should be correct, but this is more than just a couple garbage samples. The clicks and pops can happen long after the sound stopped playing, which is why I added a longer delay. It's also not a 100% consistent, e.g. sometimes there are lots of clicks, sometimes only a pop a few seconds after the sound.
|
01 April 2024, 11:20 | #4 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
I dont use audio.device especially, only for some players. I think You must add something like playing null/empty sample at end of your routine.
Anyway audio.device is buggy, missing DMAWait for fast CPU's. I dont know if it was fixed for kickstart 3.2. Then using audio.device is not very good choice for me. But if You want to see how is coded the biggest Amiga replay which using audio.device, then You can see MaxTrax original replay source (available on Wanted Team page). |
01 April 2024, 11:48 | #5 |
Going nowhere
Join Date: Oct 2001
Location: United Kingdom
Age: 50
Posts: 9,035
|
Make sure that first longword of all samples is null, that should remove clicks and pops
|
01 April 2024, 13:33 | #6 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
Yes, but it will be fix/modify data, not program.
For me the best (universal) solution is next: 1. Alloc 2 bytes longer chip ram buffer, than is necessary for sample to playing. 2. Clear first 2 bytes of this buffer. 3. Load sample to play at buffer + 2 bytes. 4. Add 1 (for audio.device, this is perhaps 2, if I remember right) to played sample length. |
01 April 2024, 22:03 | #7 |
old chunk of coal
Join Date: Nov 2011
Location: Hungary
Posts: 1,318
|
I'm trying to keep things system friendly, so I opted to use audio.device. I'm looking at the MaxTrax sources, but it seems to do some peeking and poking at the chipset registers too, I guess the audio.device limitations necessitated things like DMAWait.
Thanks for tips, I tried both 2 and 4 bytes of silence at the beginning of the sample, but the noise still persists after problematic one ends one cycle. I guess an alternate solution would be to create a softint for the reply message that does a CMD_FLUSH or something similar. |
02 April 2024, 00:23 | #8 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
I dont remember, If MaxTrax used chipset registers too. Maybe it was added by me for Volume handling for EaglePlayer.
If You still hear strange noise, then for me can be one of two possibilities. 1. Repeat sample length is greatar than 1 (2 for audio device) 2. Audio.device dont loop to begining of sample, but is stoped/looped at end of sample. If this is reason, then 2 empty bytes must be et end of sample, not at begining. From my memory Action Replay 3 has command to show Amiga chip registers values. Simple, play this sample. When strange noise occured, enter to AR3, show registers. Find audio address registers and later check which value is played. |
02 April 2024, 07:20 | #9 |
old chunk of coal
Join Date: Nov 2011
Location: Hungary
Posts: 1,318
|
I think padding the end of the sample with zeroes have fixed it! I'll give it some more testing on different setups to make sure.
|
02 April 2024, 21:58 | #10 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
Nice.
Then for fixing source code. 1. Must be allocated 2 bytes greater buffer than loaded sample of cleared chip memory. 2. And 2 bytes greater length than loaded sample must be played. |
03 April 2024, 10:17 | #11 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
After rethinking some time, perhaps sample length (to play) must be done via similar code:
Code:
move.l LoadedLength,D0 addq.l #3,D0 bclr #0,D0 Code:
bclr #0,D0 Code:
addq.l #1,D0 bclr #0,D0 Code:
addq.l #2,D0 |
03 April 2024, 20:29 | #12 |
old chunk of coal
Join Date: Nov 2011
Location: Hungary
Posts: 1,318
|
You mean rounding the length up to the next word/long boundary? I'm not sure if that'll do much in this case, as the problematic sample is 3040 bytes long.
|
04 April 2024, 01:07 | #13 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
Yes.
Try to add f.e 1000 null bytes at end of problematic sample. Maybe this sample is loaded in any special chip ram location or wrong size to playing is set? And of course some samples can be damaged too. You can hear this sample under FileMaster 2.2. Or use AR3 and check which word is playing, when problem occured. |
04 April 2024, 11:29 | #14 |
Registered User
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 56
Posts: 2,132
|
From my memory strange noises can occured, if:
1. Wrong area is played, f.e fast ram. 2. Wrong period is set. 3. Not sample data in chip mem is played. |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Crackling Noise starting Audio with theplayer routine | Emufr3ak | Coders. Asm / Hardware | 10 | 25 February 2024 17:52 |
Stereo sound with audio.device | BSzili | Coders. System | 2 | 22 February 2022 21:37 |
Video and Audio Noise in Amiga 600 Rev 1.5 | Nibbler | support.Hardware | 10 | 09 March 2020 13:01 |
Amiga 2000 that previously had sound not playing sound after repairs | DCF | support.Hardware | 1 | 18 September 2019 06:41 |
A1200 - Audio noise | NovaCoder | support.Hardware | 6 | 11 March 2012 23:57 |
|
|