Page 1 of 2

Sound the sounds

Posted: Tue Apr 18, 2006 1:31 pm
by winston
Well, I've not done any code borking recently, so it's about time to do some more.

Frantic sent me a patch (which I have STILL not looked at) for adding sounds to some events that don't have sound yet (to support an Amiga sound OXP). This means there are some extra loops required, and it's probably best in the long run to have generic sound loop code rather than various performSelector message passing shenanigans for each and every sound loop.

Loops in Oolite are currently done (IIRC) in PlayerEntity.

The next branch of experimentation I'll do will be to make some generic sound looping code. SDL_mixer even supports looping (although I'm not sure whether it'll be worthwhile for us, given that we don't know how many loops we need to make ahead of time). My basic plan is to add generic looping based on 3 samples:

- attack
- sustain
- decay

(sort of like the BBC Microcomputer had an envelope, but using samples instead of synthesising the sounds). I'll probably make a subclass of OOSound to do it. It'll be done as a separate branch so as not to intefere with the stuff that's going on in the main trunk.

Posted: Wed Apr 19, 2006 6:46 am
by JensAyton
This has been on my plate, hiding behind the mash, for a while.

I was thinking of allowing multiple versions of each segment (attack/sustain/decay) which can be automagically intermixed by the sound code. While this doesn’t need to be done first thing, it’s worth keeping in mind when designing. The simplest way would be to allow loading a plist as a sound file, which specifies each segment as a string or array.

I’d be more specific about stuff, but work calls. :-)

Posted: Wed Apr 19, 2006 8:12 am
by JensAyton
Work was less beckony than previously believed, so some expansion. I want to implement looping at a low level in OOCASound, since doing it sample-accurately is trivialish (scary word, that). Being on the same page designwise seems like a good idea. The CA implementation will probably also allow a plist-based sound to include other plist-based sounds, purely because it’s more convenient, but that might be considered abuse. Especially if it’s recursive, since the sound would never stop.

I’m thinking a super-complex API along the lines of:

Code: Select all

@interface OOSound (Looping)
- (void)playLooped;
- (void)endLoop;
@end
If -stop is called on a looping sound (or sound source) it stops immediately. If -endLoop is called on a non-looping sound, nothing happens. The existing play and stop return a BOOL, but this isn’t actually useful.

This brings up another point, though: the SDL sound code still doesn’t implement sound sources properly (this is laxity on my part, I admit). As you know, the purpose of sound sources is to support positional audio, but they also separate channels from sounds and allow more than one copy of a sound to be played at once. Implementing this in the SDL code should also be trivialish – work from OOBasicSoundSource and move the channel-grabbing code from SDLSound to the sound source. It’s probably easier to do this before loops than after.

Anywho… when a sound file is loaded, OOSound (or a subclass, or whatever; implementation detail) looks at the file extension (urgh) and if it’s a plist, loads several sub-sounds. (In CA, this will be an OOComplexSound loading several OOSounds which may themselves be OOComplexSounds or OOBufferedSounds.) The plist is a dictionary which may specify an array of “attack” or “in” sounds, an array of “sustain” sounds and an array of “out” sounds; if only one is specified in a given category, it can be specified as a string instead of an array for convenience. It may also skip one or all of the types, but if there are no sustains specified the sound won’t loop. An implementation may, for simplicity, choose to always use the first (or a random) sound from an array.

On playback, the implementation plays one of the in sounds, if any, then one of the sustain sounds, if any; as long as the sound is looped, it will then pick a new sustain sound and play that, until the loop flag is cleared by -endLoop. When the loop flag is cleared and a sustain comes to an end, an out sound, if any, is played.

Example (afterburner_sound.plist):

Code: Select all

attack = "ab_attack.ogg";
sustain = ( "ab_sustain1.ogg", "ab_sustain2.ogg" );
decay = "ab_decay.ogg";
Am I missing anything?

* Goes in search of an afterburner.aiff to chop up *

Posted: Wed Apr 19, 2006 8:41 am
by aegidian
*impressed*

I can't imagine a better way to implement that. Very cool!

Posted: Wed Apr 19, 2006 8:47 am
by winston
Great minds think alike - I was musing this morning in the shower (as you do) that really the contents of the loop should be specified by a plist. Also, have any event as either a looped sound or not as the case may be, depending on plists present (so for example, in the default game, laser sounds are not a loop, but it's quite possible that someone might want to make a looped version of a laser sound - so make the choice plistable, but that needs more thought to avoid confusion).

Posted: Wed Apr 19, 2006 9:05 am
by JensAyton
Afterburner duly cut up (working from AIFF form) and checked in to SoundLoop branch. The bits can be seamlessly combined, and the order in-sustain1-sustain2-out recreates the original sound. I also checked in flac versions in the Asset Source directory, since sound builder 3 is a somewhat specialised format.

As for looping lasers and such, that’s a higher-level issue. What it means, and whether it makes any sense at all, is context-dependant. Maybe it should be specified in the sound indirection plist Giles has been working on?

Posted: Wed Apr 19, 2006 9:48 am
by JensAyton
Hmm. I note that OOSoundSource already implements looping, but at a whole-sound level without ins and outs. It also implements playing a sound a certain number of times in a row. Is this a useful feature?

Posted: Wed Apr 19, 2006 10:13 am
by aegidian
Ahruman wrote:
As for looping lasers and such, that’s a higher-level issue. What it means, and whether it makes any sense at all, is context-dependant. Maybe it should be specified in the sound indirection plist Giles has been working on?
Mmm. Some sort of plist grammar for sounds would be good. I can image:

Code: Select all

<dict>
<key>attack<key>
<string>sound-in.ogg</string>
<key>sustain<key>
<array>
    <string>sound2.ogg</string>
    <string>sound3.ogg</string>
</array>
<key>decay<key>
<string>sound-out.ogg</string>
</dict>
Which should play sound-in..sound2..sound3..sound-out in sequence.
But should:

Code: Select all

<dict>
<key>attack<key>
<string>sound-in.ogg</string>
<key>loop<key>
<array>
    <string>sound2.ogg</string>
    <string>sound3.ogg</string>
</array>
<key>decay<key>
<string>sound-out.ogg</string>
</dict>
play sound-in..sound2..sound3..sound2..sound3..sound2..sound3.. etc ..sound-out

or should it play
sound-in..[random choice from sound2|sound3].. etc ..sound-out

?

Or should we have <key>loop-choose-from</key> and <key>loop-sequence<./key> (frex) and interpret the two differently?

Or, or, or? *brain foom*

Posted: Wed Apr 19, 2006 10:59 am
by winston
Well, the spirit of the branch is all a grand experiment :-)

It's forecasting a rainy weekend so I might get to muck around with it some without feeling the urge to try and do building work outside...

Posted: Wed Apr 19, 2006 12:49 pm
by JensAyton
I don’t really see any point in specifying sequences. They can just be combined into one file. How often will you want to cut in (as opposed to overlay) a piece in several sequences? Random selection, on the other hand, provides the opportunity for small variations. I could see an argument for weighted randomness, though.

Posted: Wed Apr 19, 2006 1:05 pm
by aegidian
I was thinking about the possibility of using speech samples and cutting them together into sequences, I have a female friend who's a voice artist and could probably do 'sexy-computer-voice' very well.

"radioactives"+pause+"destroyed"

Posted: Wed Apr 19, 2006 1:13 pm
by Murgh
what would be the name of such a sexy synthetic voice?
Elita? :D

Posted: Wed Apr 19, 2006 6:45 pm
by JensAyton
aegidian wrote:
I was thinking about the possibility of using speech samples and cutting them together into sequences, I have a female friend who's a voice artist and could probably do 'sexy-computer-voice' very well.

"radioactives"+pause+"destroyed"
Have you any idea how much work sampling and processing that sort of thing is?

But OK, that’s a reason. Assuming there’s a “radioactives destroyed” sound event, which I would hope falls back to “generic canister destroyed” if there’s no special case for it. :-)

(Note to self: a new class OOCASoundSequence: OOSound could handle this for internal-representation purposes.)

Posted: Fri Apr 21, 2006 2:51 pm
by Selezen
Murgh wrote:
what would be the name of such a sexy synthetic voice?
Elita? :D
There could only be one name for the synthetic voice.

Paula - named after the Amiga sound chip!!

Maybe everyone's g/f could contribute a sound set. If someone sends me a list of the necessary bites, I'll ask my significant other to do a set!!

Posted: Fri Apr 21, 2006 3:45 pm
by Lucidor
I actually think that the synthetic voice used now is pretty good. Your relationships will probably hang on a thin thread if you ask your girlfriends to record the names of the stars in all the galaxies. :^)