+SpiceWare Posted June 8, 2013 Share Posted June 8, 2013 Here's a preliminary sound effect driver for use with bB. I've not added anything to bB before, so I'm open to suggestions on how to make this better. sfx.zip Here's the test BIN. Joystick up/down to select a sound effect, hit FIRE to trigger it. Sound Effect 0 is a special case, it silences all output. sfx_demo.bas.bin To use in your program you need to do the following. 1. Allocate 2 of the bB variables for use by the driver: dim SFX_LEFT = y dim SFX_RIGHT = z 2. Include the driver in your bB program: inline sfx.asm 3. Trigger a sound effect whenever appropriate. (is there a way to eliminate the temp1=?) temp1=sfxtrigger(#sfxJUMP) 4. Add a call to update the sound effects. For best results, put it after every drawscreen (this is to make the updates happen at the exact time every screen): drawscreen temp1=sfxupdate() : rem for best results, update sound effect after drawscreen The sound effects are defined in 2 tables at the top of sfx.asm. The first table defines the Frequencies: sfxF: .byte 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ; Jump .byte 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ; jump 2 .byte 0, 24, 25, 26, 27, 28, 29, 30, 31 ; throw .byte 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 ; collect .byte 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; ping .byte 0, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0 ; stole .byte 0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6 ; extra .byte 0,$10,$10,$10,$10,$10,$10 ; Bonus 50 .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; Health The second table defines the Control (tone) and Volume: sfxCV: .byte 0,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf ; Jump sfxJUMP = *-sfxCV-1 .byte 0,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f ; Jump 2 sfxJUMP2 = *-sfxCV-1 .byte 0,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f; throw sfxTHROW = *-sfxCV-1 .byte 0,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f ; collect sfxCOLLECT = *-sfxCV-1 .byte 0,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f ; ping sfxPING = *-sfxCV-1 .byte 0,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f ; stole sfxSTOLE = *-sfxCV-1 .byte 0,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f ; extra sfxEXTRA = *-sfxCV-1 .byte 0,$40,$40,$4f,$4f,$4f,$4f ; bonus sfxBONUS50 = *-sfxCV-1 .byte $0,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f,$7f ; Full Health sfxHEALTH = *-sfxCV-1 Each .byte line contains the data for a single sound effect. The two tables are used together, so data in the first .byte line in sfxF goes along with the data in the first .byte line in sfxCV. The number of values must be the same in each table and each .byte line. The first value in each .byte line should be 0, it denotes end-of-sfx. Table sfxCV looks a little complicated because of the extra lines such as sfxJUMP = *-sfxCV-1. All those are doing is calculating the value to be used when you trigger a sound effect. You can name your sound effects whatever you want, just make sure it's followed by = *-sfxCV-1 (also make sure you have a space before and after the equal sign). Lets look at a single sound effect to explain how the data is used: sfxF: .byte 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 ; Jump sfxCV: .byte 0,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf ; Jump sfxJUMP = *-sfxCV-1 When you trigger a JUMP sound effect by the function temp1=sfxtrigger(#sfxJUMP), a sound effect pointer will be initialized so that it points to the 26 in the sfxF table and the $cf in the sfxCV table. When you update the TIA sound registers by calling temp1=sfxupdate(), the 26 goes into AUDFx while $cf is split into two parts with the c going into AUDCx and the f going into AUDVx. Lastly the pointer gets updated so it now points to 25 and $ce for the next call to sfxupdate. 6 Quote Link to comment Share on other sites More sharing options...
Rabbit 2600 Posted June 8, 2013 Share Posted June 8, 2013 Sweet! Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted June 9, 2013 Author Share Posted June 9, 2013 (edited) So far this morning I've added some validation checks for the sound effect tables. These check that the tables are not too large (max size is 256 bytes), plus they check that the tables are the same size. ~/Projects/Atari/bB11d/sfx> 2600basic.sh sfx_demo.bas Starting build of sfx_demo.bas batari Basic v1.01 (C)2005-2007 (40) Warning: function call with no arguments (54) Warning: function call with no arguments 2600 Basic compilation complete. SFX Warning: table sfxF is too large SFX Warning: table sfxCV is too large SFX Warning: table sfxF is not the same size as table sfxCV bytes of ROM space left SFX Warning: table sfxF is too large SFX Warning: table sfxCV is too large SFX Warning: table sfxF is not the same size as table sfxCV 1880 bytes of ROM space left Build complete. The two "no arguments" warnings are for these lines: if sound_effect = 0 then temp1=sfxoff() ... temp1=sfxupdate() Is there way to eliminate that warning, or a different way to set up sfxoff and sfxupdate so the bB compiler knows that "no arguments" is OK for those two functions? It'd be nice to eliminate the assignment requirement too (the temp1= part of the command) as that'll save 2 bytes of ROM for each function call. Edited June 9, 2013 by SpiceWare Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted June 9, 2013 Author Share Posted June 9, 2013 (edited) Looks like I neglected to include a comment about sound effect priority. Since there's only 2 sound channels, the Atari can only play 2 concurrent sound effects. My routine is set up with a priority system so that if 2 sound effects are currently playing then a new call to sfxtrigger will override one of the currently playing sound effects only if the new sound effect has a higher priority. The priority is controlled by the order the sound effects are defined. In the sfxCV table, listed in the first post, you can see that the sound effects are defined in this order: sfxJUMP sfxJUMP2 sfxTHROW sfxCOLLECT sfxPING sfxSTOLE sfxEXTRA sfxBONUS50 sfxHEALTH The first sound effect has the lowest priority, the last sound effect has the highest. If 2 sound effects are currently playing then the command temp1=sfxtrigger(#sfxJUMP) will be ignored while temp1=sfxtrigger(#sfxHEALTH) will always occur. For a real game example, in Space Rocks my sound effects are defined in this order: sfxHeartbeat1 sfxHeartbeat2 sfxThrust sfxFlip180 sfxPlayerShoot sfxSaucerShoot sfxSmallAsteroidHit sfxMediumAsteroidHit sfxLargeAsteroidHit sfxShields sfxSmallUFO sfxLargeUFO sfxSmallSaucerHit sfxLargeSaucerHit sfxPlayerHit sfxWarpIn sfxMagnaMine sfxMenuBlip sfxExtraShip The order of sound effects was carefully selected. The Heartbeat and Thrust sound effects are background noise. It's no big deal if you don't hear them, so they're first in the list to denote that they have the lowest priority. The asteroid explosion sound effects are ordered Small, Medium, then Large as a large explosion would "drown out" a medium or small explosion. The MagnaMine and ExtraShip are highest priority as when those occur you always want the player to know. The MenuBlip will never occur during game play, so it's priority position doesn't really matter. Edited June 9, 2013 by SpiceWare Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted June 10, 2013 Share Posted June 10, 2013 Is there a way to import from, say, sfxr? http://www.drpetter.se/project_sfxr.html Or a utility to generate samples for your sound engine? Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted June 10, 2013 Author Share Posted June 10, 2013 (edited) Looks like sfxr creates WAV files, which won't work with this driver. PacManPlus has a tool which he used to create the sound effects for Space Rocks. I'm not familiar with his tool, nor do I know if he's made it (or plans to make it) available for others. I do know his tool is used with a Korg X5D though, so if you don't have one the tool wouldn't be useful. Space Rocks also uses a more advanced driver, which packs a duration count in with the frequency data. The currently bB driver uses the data at a rate of 1 entry per screen, the advanced one lets you hold a value for up to 8 frames. However, to keep track of duration, the advanced driver needs you to give up 2 more bB variables. RAM is tight in bB, which is why I ported the simpler driver first. I should be able to rewrite the driver to only need 1 extra bB variable instead of 2, it'll just take more ROM to do so. I plan to port the advanced driver once this one is finalized. This will give people a choice on which driver to use based on how many bB variables they're willing to give up. What I envision is people sharing sound effects for the driver. Something along the lines of a topic with posts like this: Space Rocks Shot sound effect sfxF: .byte 0, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14 ; Player Shoots sfxCV: .byte 0,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c ; Player Shoots sfxSHOOT = *-sfxCV-1 Then others would just copy the data into their tables. Edited June 10, 2013 by SpiceWare Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted June 10, 2013 Share Posted June 10, 2013 Thanks for your work on this. I'm sure a standard sound effect engine would be as useful as the music engine has been for VisualbB users. Hopefully someone will come up with a side project to create waveforms for this. Quote Link to comment Share on other sites More sharing options...
bogax Posted June 10, 2013 Share Posted June 10, 2013 (edited) I really have no experience with this (Atari sounds) and what someone might want. After looking at mostly theloon's sound effects I was thinking something like this Choose voice from a subset of the possible values so that it could be packed in a byte with frequency. I wonder if volume could be compressed in a similar way 3 bits of roughly log scale for volume 5 bits for duration a 0 byte delimits sounds bytes are in pairs the byte paired with zero selects which voice subset to use. a variable for each channel for voice subset table pointer and duration counter. edit ack 3 bits of roughly log scale for VOLUME 5 bits for duration edit2 double ack Edited June 10, 2013 by bogax Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted June 10, 2013 Author Share Posted June 10, 2013 (edited) There's many ways to write a sound driver, I'm only planning to port the two I currently use. I won't feel slighted in the least if you write another driver if mine doesn't do what you need. As far as compression, the data for my advanced driver would shrink this 20 bytes of sound effect data: sfxF: .byte 0,$13,$13,$13,$13 ; heartbeat1 .byte 0,$16,$16,$16,$16 ; heartbeat2 sfxCV: .byte 0, $6f,$6f,$6f,$6f sfxHEART1 = *-sfxCV-1 .byte 0, $6f,$6f,$6f,$6f sfxHEART2 = *-sfxCV-1 down to 8 bytes of data: sfxF: .byte 0, D4 + $13 ; heartbeat1 .byte 0, D4 + $16 ; heartbeat2 sfxCV: .byte 0, $6f sfxHEART1 = *-sfxCV-1 .byte 0, $6f sfxHEART2 = *-sfxCV-1 The D4 is one of the eight duration constants: D1 = 0 D2 = 1*32 D3 = 2*32 D4 = 3*32 D5 = 4*32 D6 = 5*32 D7 = 6*32 D8 = 7*32 The compression can potentially lot of ROM, at the expense of using more RAM. There isn't always a ROM savings though - if you look at the data in the first post you see this: sfxJUMP - cannot be compressed, sfxF value changes on every frame sfxJUMP2 - cannot be compressed, sfxF value changes on every frame sfxTHROW - cannot be compressed, sfxF value changes on every frame sfxCOLLECT - can be compressedsfxF: .byte 0, D3+1, D3+2, D3+3sfCV: .byte 0, $6f, $6f, $6f sfxPING - cannot be compressed, sfxCV value changes on every frame sfxSTOLE - can be compressedsfxF: .byte 0, D3+3, D3+2, D3+1, D3+0sfxCV: .byte 0, $6f, $6f, $6f, $6f sfxEXTRA - cannot be compressed, sfxF value changes on every frame sfxBONUS50 - can be compressedsfxF: .byte 0, D2+$10, D4+$10sfxCV: .byte 0, $40, $4f sfxHEALTH - cannot be compressed, sfxF value changes on every frame One benefit of my driver, provided you're not writing a game that utilizes stereo sound, is you no longer have to worry about assigning channels to sound effects as the driver automatically selects a channel for you. The driver first looks for an idle channel, if it can't find an idle one it then uses priority to determine if the requested sound effect should be played or ignored. Edited June 10, 2013 by SpiceWare Quote Link to comment Share on other sites More sharing options...
bogax Posted June 10, 2013 Share Posted June 10, 2013 (edited) LIke I said I realy know nothing about it I was only thinking about it because theloon mentioned it once. Mostly I wonder if using a subset of voices is practical. I suspect a log scale for volume would work out just fine. 5 bits for duration seems like more than enough, maybe too much. but I hadn't thought of anything to use an extra bit for of course it would be simpler to just make it 4 bits volume and 4 bits duration Now you've got me thinking about prioritizing sound effects edit and automatically assigning channels As to compression another possibility I was thinking of exploring is doing something more stream like and using difference compression (which looks like it would do just fine for your jumps) I expect that's overkill though, and you'd probably have to have a custom editor to make it usable I was planning on doing it all in bB I was thinking about rewriting yours in bB just for the hell of it. Edited June 10, 2013 by bogax Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted June 10, 2013 Author Share Posted June 10, 2013 Mostly I wonder if using a subset of voices is practical. There's only 2 voices (the channels), so using a subset would mean only 1 sound effect at a time. I was planning on doing it all in bB I was thinking about rewriting yours in bB just for the hell of it. Go for it. Quote Link to comment Share on other sites More sharing options...
bogax Posted June 10, 2013 Share Posted June 10, 2013 There's only 2 voices (the channels), so using a subset would mean only 1 sound effect at a time. . I meant the control each channel has frequency, volume and control (voice) and restricting it to a subset of 8 of the possible 15 (of which 5 are redundant anyway according to RT's page) Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted June 10, 2013 Author Share Posted June 10, 2013 Ah - that's a good idea. You can disregard Control = 0 as well; that's only useful for playing back digital samples, which requires advanced coding that's not possible with bB. For digital samples you must update AUDVx on every-single-scanline, even during vertical blank and overscan. Quote Link to comment Share on other sites More sharing options...
iesposta Posted June 21, 2013 Share Posted June 21, 2013 This will help me in making sound effects. I had simple music figured out, but sound effects was stopping me. Not only did Rev Eng help me with his priority sound effect routine, but now there is Spiceware's also! I should stop taking such long vacations, so much happens... Quote Link to comment Share on other sites More sharing options...
RevEng Posted June 21, 2013 Share Posted June 21, 2013 You can disregard Control = 0 as well; that's only useful for playing back digital samples[...] Actually there's one more use. If you change the volume level once (instead of toggling it at audible frequencies) you get a short snap of higher frequencies that makes a nice understated percussive sound. I used this as a lead-in beat to the 21 blue ditty. 1 Quote Link to comment Share on other sites More sharing options...
Mountain King Posted February 10, 2016 Share Posted February 10, 2016 I didn't know this existed. I can't wait to try it. It could have saved me from making splat noises over and over. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted February 10, 2016 Share Posted February 10, 2016 I didn't know this existed. I can't wait to try it. It could have saved me from making splat noises over and over. Have you tried making sounds with the Music and Sound Editor? Quote Link to comment Share on other sites More sharing options...
Mountain King Posted February 10, 2016 Share Posted February 10, 2016 Have you tried making sounds with the Music and Sound Editor? I used that to write the Gizzle Wap song, but not sound effects. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted February 11, 2016 Share Posted February 11, 2016 I used that to write the Gizzle Wap song, but not sound effects. It's great for making sound effects. You can have fun trying to weave Atari 2600 sounds that you haven't heard a million times before. Every sound effect in Seaweed Assault and ChipOff were made using the Music and Sound Editor. Quote Link to comment Share on other sites More sharing options...
+Karl G Posted June 5, 2017 Share Posted June 5, 2017 This driver is quite awesome! It makes sound so much easier to deal with. Thank you so much for providing this. The current version is perfect for my game, but for one that had music of any non-trivial length, I would think that the 4-byte version would be worth the ROM savings. Here are two sound effects I have made. I'm happy with my ship shooting noise: sfxF: .byte 0, 8, 7, 7, 6, 5, 4, 3, 2, 2, 3 ; Player fires sfxCV: .byte $0,$16,$18,$18,$1A,$1B,$1C,$1D,$1F,$1D ; Player fires sfxFIRE = *-sfxCV-1 I think my explosion sound could be improved, although I'm not sure how to do so: sfxF: .byte 0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 ; Explosion sfxCV: .byte 0,$82,$84,$86,$88,$86,$88,$86,$88,$86,$88 ; Explosion sfxEXPLODE = *-sfxCV-1 I could really use an alien-sounding shooting noise, but I haven't yet had luck making one that sounds at all good. 2 Quote Link to comment Share on other sites More sharing options...
+Muddyfunster Posted September 9, 2019 Share Posted September 9, 2019 (edited) Am I right in thinking that I can only use the driver in the same back that I call the inline ASM? I've tried an out of bank call to the sfx update with no joy. I use this on Dare Devil in the main loop for sfx and it works great, what I need to do is generate a sound effect from a different part of the code in a different bank and that's where I'm struggling. I also find when using the driver, other sounds get distorted. I thought the driver checked for an available channel and then used it if it was free, so for example, if i'm using channel 0 for music/whatever, the driver asm checks and sees that is the case and sends the sfx to channel 1? Edited September 9, 2019 by Muddyfunster Quote Link to comment Share on other sites More sharing options...
+Karl G Posted September 9, 2019 Share Posted September 9, 2019 Yes, it needs to be called from the same bank where it is included. I was thinking you already ran into this with Tyre Trax? What I did is make a wrapper function in the correct bank that in turn calls the SFX driver, and then I did my bankswitch gosub to that wrapper function from where I needed it. Let me know if any examples would be helpful. Also, the driver has no way of knowing if a channel is in use; it just knows if it is using a channel itself to play a sound. I don't know if there is even a way programmatically to determine if sound registers are being used, and even if there was, that would fail in certain cases if the music was at a "rest" at the time the sound register is checked. The way I handled this myself was to set a bit if music was playing, and check for this bit before calling the SFX driver to avoid conflicts. E.g.: if !MusicPlayingBit6{6} then temp1=sfxupdate() 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.