C Sound Libraries
- barnsey123
- Flight Lieutenant
- Posts: 379
- Joined: Fri Mar 18, 2011 10:04 am
- Location: Birmingham
C Sound Libraries
Has anyone got any sound libraries for use in C programs? I'm looking for various sound effects to supplement/replace the ROM routines.
In particular, anything metallic (clash of swords, hammer on anvil? etc)
Any advice would be welcome.
In particular, anything metallic (clash of swords, hammer on anvil? etc)
Any advice would be welcome.
You can try to use the following function:
void w8912(unsigned char reg,unsigned char value);
It's very low level, but with that you have access to all the registers of the sound-chip.
Alternatively, if you have some free memory, and if you can afford to not do anything while a sound is playing, then possibly you could just replay sample sounds, either using 8 bits or 4 bit samples.
As usual, it's a size/cost/quality trade-off
Imo, if you have few kilobytes free, sample sounds could be cool, because with that you can even have voices, growls, laughs, etc...
void w8912(unsigned char reg,unsigned char value);
It's very low level, but with that you have access to all the registers of the sound-chip.
Alternatively, if you have some free memory, and if you can afford to not do anything while a sound is playing, then possibly you could just replay sample sounds, either using 8 bits or 4 bit samples.
As usual, it's a size/cost/quality trade-off
Imo, if you have few kilobytes free, sample sounds could be cool, because with that you can even have voices, growls, laughs, etc...
Re: C Sound Libraries
OK, this post is a bit old... but
Since a few, I am working about sound effects with Oric, the way they are generated by PING, EXPLODE or SHOOT (Not zap, because, it does not works the same way).
According to Theoric (Special issue, August 1985, page 36/37) , it works as it :
You have a table of 14 bytes at some address.
for PING, it is located at #FAA7( 64167) : 24,0,0,0,0,0,0,62,16,0,0,0,15,0
for SHOOT, at #FABD( 64189) : 0,0,0,0,0,0,15,7,16,16,16,0,8,0
for EXPLODE, at #FAD3( 64211) : 0,0,0,0,0,0,31,7,16,16,16,0,24,0
Whenever you call PING, SHOOT or EXPLODE :
1 ) Register X is loaded with lower order byte of the table starting address
2 ) Register Y is loaded with higher order byte of the table starting address
3) an Oric routine is called, playing the sound with this table.
Calling SHOOT, calls this piece of code
(JSR #FA6C for Oric1)
by trying and guess, luck I discovered a few interesting sound effects :
Electricity : 0,4,0,184,0,3,120,190,12,0,0,0,167,194
Helicopter : 168,191,0,3,184,191,14,0,0,0,167,194,76,176
Engine : 1,5,193,7,7,8,7,8,53,151,47,151,0,152
Inside the cockpit of a plane : 150,0,152,46,4,255,255,112,7,80,0,102,5,65
A plane (turboprop) : 32,2,140,0,5,132,14,136,132,12,140,0,69,173
Helicopter (far away) : 14,136,132,12,140,0,69,173,0,5,208,4,169,192
Forge hammer hitting an anvil : 32,134,250,96,0,0,0,0,0,0,31,7,16,16
all of these have to be a bit cleaned up (it's a non sense to have some data for channel A for instance, but with channel A non-activated)
found on the web, here (another helicopter) :
206,108,231,36,137,112,70,182,170,239,83,246,12,165
Found in the Theoric magazine :
PONG : EE 02 00 00 00 00 00 3E 10 00 00 D0 07 00
PCHH: 00 00 00 00 00 00 01 37 10 00 00 D6 0B 00
Now, what is the meaning of each byte of the table ?
Simply, they correspond to the AY-3-8912 registers :
- 0 and 1 : tone (pitch) on channel A (n between 0 and 4096) (12 bits)
- 2 et 3 : tone (pitch) on channel B (between 0 and 4096) (12 bits)
- 4 et 5 : tone (pitch) on channel C (between 0 and 4096) (12 bits)
note:n=real_period/16/T0 (TO=1µS for Oric) or in short Frequency=1MHz/16/n (n=0 acts as n=1)
Possible frequencies are in range from 62500Hz (n=1) down to approx. 15.26Hz (n=4095)
6 : period of the noise generator (between 0 and 31) note: only bits 0 to 4 are used, Frequency=1MHz/16/n (n=0 acts as n=1)
7: Channels activation
bit 0: channel A
bit 1: channel B
bit 2: channel C
bit 3,4 et 5 mixing of the noise into the three primary channels
becarefull: bit=0 means "activated" bit=1 means NOT activated, for the 6 bits
(note: bit 6 is the port A direction and bit 7 the port B direction, not used for sound generation)
8,9,10 --> volume A,B,C (0 to 16)
more precisely :
- bits 0 to 3 (amplitude): maximum amplitude or volume (0 to 15)
- bit 4 (modulation) : 0 -->fixed amplitude 1-->amplitude controlled by B0-B3 and the envelop generator
Note : The volume is non-linear. The "real world" amplitude can be computed like this :
This amplitude corresponds to the voltage output to a speaker. (15 --> max/1, 14 --> max/1.414, 13 --> max/2, etc...)
11 and 12 --> Envelope step frequency - sound duration - (0 to 65535) note:Frequency=1MHz/16/n (n=0 acts as n=1)
Depending on the envelope shape, the volume is incremented from 0 to 15, or decremented from 15 to 0. In either case it takes 16 steps to complete, the completion time for 16 steps is therefore:
13 --> envelop (0 to 15) note:only bits 0 to 3 are used.
According to wikipedia (french) : bits 0 to 3 permit to control the sound envelop but only 10 are available because only B2 is taken into account when B3 is equal to zero :
Registers+envelops :
http://download.abandonware.org/magazin ... e%2021.jpg
Pong sample for OSDK :
main.c
pongsound.s
There's a lot to dig in with this, because it is rather simple to put in practice, it does not consume a lot of memory.
Moreover (I would like to study that closely), it may be interesting to look out around with what can exist for the cpc464, for instance, or other microcomputer, for instance :
https://cpcrulez.fr/coding_basic-le_son_sur_AMSTRAD.htm
https://cpcrulez.fr/coding_src-list-sou ... mstrad.htm
Since a few, I am working about sound effects with Oric, the way they are generated by PING, EXPLODE or SHOOT (Not zap, because, it does not works the same way).
According to Theoric (Special issue, August 1985, page 36/37) , it works as it :
You have a table of 14 bytes at some address.
for PING, it is located at #FAA7( 64167) : 24,0,0,0,0,0,0,62,16,0,0,0,15,0
for SHOOT, at #FABD( 64189) : 0,0,0,0,0,0,15,7,16,16,16,0,8,0
for EXPLODE, at #FAD3( 64211) : 0,0,0,0,0,0,31,7,16,16,16,0,24,0
Whenever you call PING, SHOOT or EXPLODE :
1 ) Register X is loaded with lower order byte of the table starting address
2 ) Register Y is loaded with higher order byte of the table starting address
3) an Oric routine is called, playing the sound with this table.
Calling SHOOT, calls this piece of code
Code: Select all
ldx #$BD
ldy #$FA
JSR $FA86
RTS
by trying and guess, luck I discovered a few interesting sound effects :
Electricity : 0,4,0,184,0,3,120,190,12,0,0,0,167,194
Helicopter : 168,191,0,3,184,191,14,0,0,0,167,194,76,176
Engine : 1,5,193,7,7,8,7,8,53,151,47,151,0,152
Inside the cockpit of a plane : 150,0,152,46,4,255,255,112,7,80,0,102,5,65
A plane (turboprop) : 32,2,140,0,5,132,14,136,132,12,140,0,69,173
Helicopter (far away) : 14,136,132,12,140,0,69,173,0,5,208,4,169,192
Forge hammer hitting an anvil : 32,134,250,96,0,0,0,0,0,0,31,7,16,16
all of these have to be a bit cleaned up (it's a non sense to have some data for channel A for instance, but with channel A non-activated)
found on the web, here (another helicopter) :
206,108,231,36,137,112,70,182,170,239,83,246,12,165
Found in the Theoric magazine :
PONG : EE 02 00 00 00 00 00 3E 10 00 00 D0 07 00
PCHH: 00 00 00 00 00 00 01 37 10 00 00 D6 0B 00
Now, what is the meaning of each byte of the table ?
Simply, they correspond to the AY-3-8912 registers :
- 0 and 1 : tone (pitch) on channel A (n between 0 and 4096) (12 bits)
- 2 et 3 : tone (pitch) on channel B (between 0 and 4096) (12 bits)
- 4 et 5 : tone (pitch) on channel C (between 0 and 4096) (12 bits)
note:n=real_period/16/T0 (TO=1µS for Oric) or in short Frequency=1MHz/16/n (n=0 acts as n=1)
Possible frequencies are in range from 62500Hz (n=1) down to approx. 15.26Hz (n=4095)
6 : period of the noise generator (between 0 and 31) note: only bits 0 to 4 are used, Frequency=1MHz/16/n (n=0 acts as n=1)
7: Channels activation
bit 0: channel A
bit 1: channel B
bit 2: channel C
bit 3,4 et 5 mixing of the noise into the three primary channels
becarefull: bit=0 means "activated" bit=1 means NOT activated, for the 6 bits
(note: bit 6 is the port A direction and bit 7 the port B direction, not used for sound generation)
8,9,10 --> volume A,B,C (0 to 16)
more precisely :
- bits 0 to 3 (amplitude): maximum amplitude or volume (0 to 15)
- bit 4 (modulation) : 0 -->fixed amplitude 1-->amplitude controlled by B0-B3 and the envelop generator
Note : The volume is non-linear. The "real world" amplitude can be computed like this :
Code: Select all
real_world_amplitude = max / sqrt(2)^(15-n),
11 and 12 --> Envelope step frequency - sound duration - (0 to 65535) note:Frequency=1MHz/16/n (n=0 acts as n=1)
Depending on the envelope shape, the volume is incremented from 0 to 15, or decremented from 15 to 0. In either case it takes 16 steps to complete, the completion time for 16 steps is therefore:
Code: Select all
T = n*256 / 1MHz ;with n in range 1..65535 (256µs .. 16.7 seconds)
According to wikipedia (french) : bits 0 to 3 permit to control the sound envelop but only 10 are available because only B2 is taken into account when B3 is equal to zero :
Code: Select all
B3 - Continue
B2 - Attack
B1 - Alternate
B0 - Hold
Code: Select all
Binary Hex Shape
00XX 00h-03h \_________ (same as 09h)
01XX 04h-07h /_________ (same as 0Fh)
1000 08h \\\\\\\\\\
1001 09h \_________ (volume remains quiet)
1010 0Ah \/\/\/\/\/
1011 0Bh \""""""""" (volume remains high)
1100 0Ch //////////
1101 0Dh /""""""""" (volume remains high)
1110 0Eh /\/\/\/\/\
1111 0Fh /_________ (volume remains quiet)
http://download.abandonware.org/magazin ... e%2021.jpg
Pong sample for OSDK :
main.c
Code: Select all
#include <lib.h>
void Pong();
void main()
{
setflags(SCREEN+NOKEYCLICK);
while(get()!='Q') Pong();
}
Code: Select all
Pongtable
.byt 238,2,0,0,0,0,0,62,16,0,0,208,7,0
_Pong
ldx #<Pongtable
ldy #>Pongtable
jsr $FA86
rts
Moreover (I would like to study that closely), it may be interesting to look out around with what can exist for the cpc464, for instance, or other microcomputer, for instance :
https://cpcrulez.fr/coding_basic-le_son_sur_AMSTRAD.htm
https://cpcrulez.fr/coding_src-list-sou ... mstrad.htm
Last edited by waskol on Wed Oct 10, 2018 12:43 pm, edited 2 times in total.
Re: C Sound Libraries
I wonder if we can find random sequences of bytes in ROM that would create decent sounds
Re: C Sound Libraries
My "trying and guess" are coming from this "random " exploration, I used those values :
- for y --> 0
- for x --> 11,12,13, 14 ,23 , 25, 147, 149,154,165,184,185
some interesting sounds too with y=$FA (like for SHOOT, PING EXPLODE), testing x from 0 to 255
Adding the "Anvil/Hammer metallic sound for the final of Oric Kong (when all the metallic structure of the building is falling down)
For sure it opens soooooooooooo many possibilities to the Oric World.
I am very surprised that nobody digged that out since 80's
Just for the pleasure to see how it is simple to use it in BASIC too :
- for y --> 0
- for x --> 11,12,13, 14 ,23 , 25, 147, 149,154,165,184,185
some interesting sounds too with y=$FA (like for SHOOT, PING EXPLODE), testing x from 0 to 255
Adding the "Anvil/Hammer metallic sound for the final of Oric Kong (when all the metallic structure of the building is falling down)
For sure it opens soooooooooooo many possibilities to the Oric World.
I am very surprised that nobody digged that out since 80's
Just for the pleasure to see how it is simple to use it in BASIC too :
Code: Select all
10 FOR X=#400 TO #415
20 READ R : POKE X,R : NEXT
40 DATA #A2,#8 'LDX $8 (data file - low)
50 DATA #A0,#4 'LDY $4 (data file - high)
60 DATA #20,#6C,#FA 'JSR $FA6C (for Atmos replace #6C by #86)
70 DATA #60 'RTS
80 REM HERE COMES THE 14 BYTE DATA FILE
90 REM CHANGE THE VALUES IF YOU LIKE
100 DATA 32,134,250,96,0,0,0,0,0,0,31,7,16,16
120 POKE#26A,11
130 CLS
140 PRINT "Hit the anvil with your hammer by"
145 PRINT "pressing any key !"
150 GET A$
160 CALL#400
170 GOTO 150
Last edited by waskol on Tue Oct 09, 2018 9:59 pm, edited 1 time in total.
Re: C Sound Libraries
Nice effects and useful too!
Re: C Sound Libraries
Someone did: Twilighte, of course. Do you remember this thread? viewtopic.php?f=15&t=516
In fact I used that technique for the sfx in 1337. However, the effects produced this way are quite simple and do not offer many possibilities. I took a totally different path for Oricium, but it is also much more complicated as my engine (it is documented and the sources are in the repo) is used for playing the music too.
A quick note... you can replace the jsr xxxx / rts pair with a jmp xxxx. 1 byte and some cycles are saved this way.
In fact I used that technique for the sfx in 1337. However, the effects produced this way are quite simple and do not offer many possibilities. I took a totally different path for Oricium, but it is also much more complicated as my engine (it is documented and the sources are in the repo) is used for playing the music too.
A quick note... you can replace the jsr xxxx / rts pair with a jmp xxxx. 1 byte and some cycles are saved this way.
Re: C Sound Libraries
I was not sure about that, I am a very beginner in machine code.
I was wondering to if there was a possibility to call a C array from a function in order to load the x index and y index with the address in argument, like this :
Code: Select all
unsigned char mysoundfx[14];
...
soundfx(&mysoundfx);
OK, I found another way (see above), but it was a practice question to myself, just wondering how to do it.
Edit : I found a way, but it's ugly (OSDK article about "preprocessor abuse")
Code: Select all
#define soundfx(soundtableadr) ldx #<soundtableadr:ldy #>soundtableadr:jmp $FA86
PS : between I have edited my preceeding post to show a BASIC (funny if it is) example
PS2 : some more details and clarifications about the registers and envelops in my first post
- NekoNoNiaow
- Flight Lieutenant
- Posts: 272
- Joined: Sun Jan 15, 2006 10:08 pm
- Location: Montreal, Canadia
Re: C Sound Libraries
I love the idea, it would allow to play nice sounds using only a two bytes index into the corresponding address.
I guess it would be quite easy to write a small C program to incrementally "play" the entire ROM this way, one "sample" every two seconds with a few keyboard commands to pause/rewind/save when an interesting sound is heard.