Variable sound frequency/rate/speed changing
Moderator: InsideQC Admins
11 posts
• Page 1 of 1
Variable sound frequency/rate/speed changing
How would this go about? I mean, individual sounds varying in pitch. I've tried messing with redoing ResampleSfx... making second sound data to resample in a soundcache to playback, and messing with the 8bit channel painter directly all to noisy and hang failures.
The paintbuffer system is too restrictive for it it seems. The only way I can think about doing it is secondary cache data to resample an altered sound every time one starts, a very hoggy workaround.
The thing is, Quake resamples all sounds to the mixing rate on load, and plays those resampled bytes only. Resampling them again just causes a crash.
Half-Life pulled it off by editing SND_PaintChannelFrom8 (suggested highly as so, as in half-life, frequency doesn't change on 16-bit sounds)
andrewj?
The paintbuffer system is too restrictive for it it seems. The only way I can think about doing it is secondary cache data to resample an altered sound every time one starts, a very hoggy workaround.
The thing is, Quake resamples all sounds to the mixing rate on load, and plays those resampled bytes only. Resampling them again just causes a crash.
Half-Life pulled it off by editing SND_PaintChannelFrom8 (suggested highly as so, as in half-life, frequency doesn't change on 16-bit sounds)
andrewj?
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
i even tried to put in the apogee sound system for this purpose to terrible unstable results (involving memory and buffering usually)
The old popular solution was once to link with the FMOD library, but the dependency of FMOD runs into legal conflicts with the GPL and the "non-commercial use only" clause of the library and so everyone cried foul and we don't have fmod in anything anymore. This might seem unusual when you have all those Doom ports using FMOD and FMODEx out there, but that's how it all went down. The main use of it was underwater pitch changes and timescale pitch changes, since achieving TEH MATRIX BULLET TIMES was totally a fad in 2000-2001 when Max Payne wasn't out yet... though since then there's this unclear answer and this little debate.
Makes me wonder - how would linking to DUMB work out? A module player library used for sound effects, that is...
The old popular solution was once to link with the FMOD library, but the dependency of FMOD runs into legal conflicts with the GPL and the "non-commercial use only" clause of the library and so everyone cried foul and we don't have fmod in anything anymore. This might seem unusual when you have all those Doom ports using FMOD and FMODEx out there, but that's how it all went down. The main use of it was underwater pitch changes and timescale pitch changes, since achieving TEH MATRIX BULLET TIMES was totally a fad in 2000-2001 when Max Payne wasn't out yet... though since then there's this unclear answer and this little debate.
Makes me wonder - how would linking to DUMB work out? A module player library used for sound effects, that is...
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
Well I took a crack at it, but couldn't be bothered finishing the job (am I lazy or what?). The following diffs is what I did to tyrquake, in case it helps
Basic idea is to change 'pos' field in channel_t to 24.8 fixed point and add a 'step' field in channel_t (also fixed point).
BTW I don't think DUMB will help much.
Changed sound.h :
Changed snd_dma.c (S_StartSound) :
Changed snd_mix.c :
Basic idea is to change 'pos' field in channel_t to 24.8 fixed point and add a 'step' field in channel_t (also fixed point).
BTW I don't think DUMB will help much.
Changed sound.h :
- Code: Select all
--- sound_h_orig 2010-11-03 17:05:25.000000000 +1100
+++ include/sound.h 2010-11-03 17:05:53.000000000 +1100
@@ -74,16 +74,17 @@
// !!! if this is changed, it much be changed in asm_i386.h too !!!
typedef struct {
sfx_t *sfx; // sfx number
int leftvol; // 0-255 volume
int rightvol; // 0-255 volume
int end; // end time in global paintsamples
int pos; // sample position in sfx
+ int step;
int looping; // where to loop, -1 = no looping
int entnum; // to allow overriding a specific sound
int entchannel; //
vec3_t origin; // origin of sound effect
vec_t dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
} channel_t;
Changed snd_dma.c (S_StartSound) :
- Code: Select all
--- snd_dma_orig 2010-11-03 17:06:31.000000000 +1100
+++ common/snd_dma.c 2010-11-03 17:36:13.000000000 +1100
@@ -456,20 +456,23 @@
/* spatialize */
memset(target_chan, 0, sizeof(*target_chan));
VectorCopy(origin, target_chan->origin);
target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
target_chan->master_vol = vol;
target_chan->entnum = entnum;
target_chan->entchannel = entchannel;
SND_Spatialize(target_chan);
+ //@@@
+ target_chan->step = 192 + (rand() & 127);
+
if (!target_chan->leftvol && !target_chan->rightvol)
return; /* not audible at all */
/* new channel */
sc = S_LoadSound(sfx);
if (!sc) {
target_chan->sfx = NULL;
return; /* couldn't load the sound's data */
}
@@ -483,21 +486,21 @@
*/
check = &channels[NUM_AMBIENTS];
for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS;
ch_idx++, check++) {
if (check == target_chan)
continue;
if (check->sfx == sfx && !check->pos) {
skip = rand() % (int)(0.1 * shm->speed);
if (skip >= target_chan->end)
skip = target_chan->end - 1;
- target_chan->pos += skip;
+ target_chan->pos += skip << 8; //@@
target_chan->end -= skip;
break;
}
}
}
void
S_StopSound(int entnum, int entchannel)
{
int i;
Changed snd_mix.c :
- Code: Select all
--- snd_mix_orig 2010-11-03 18:34:23.000000000 +1100
+++ common/snd_mix.c 2010-11-03 17:32:08.000000000 +1100
@@ -250,55 +250,62 @@
void
SND_PaintChannelFrom8(channel_t *ch, sfxcache_t *sc, int count)
{
int data;
int *lscale, *rscale;
unsigned char *sfx;
int i;
if (ch->leftvol > 255)
ch->leftvol = 255;
if (ch->rightvol > 255)
ch->rightvol = 255;
lscale = snd_scaletable[ch->leftvol >> 3];
rscale = snd_scaletable[ch->rightvol >> 3];
- sfx = (signed char *)sc->data + ch->pos;
+
+ sfx = (signed char *)sc->data; //@@@
for (i = 0; i < count; i++)
{
- data = sfx[i];
+ //@@@
+ data = sfx[ch->pos >> 8];
paintbuffer[i].left += lscale[data];
paintbuffer[i].right += rscale[data];
- }
- ch->pos += count;
+ //@@@
+ ch->pos += ch->step;
+ if ((ch->pos >> 8) >= sc->length) break;
+ }
}
#endif /* USE_X86_ASM */
void
SND_PaintChannelFrom16(channel_t *ch, sfxcache_t *sc, int count)
{
int data;
int left, right;
int leftvol, rightvol;
signed short *sfx;
int i;
leftvol = ch->leftvol;
rightvol = ch->rightvol;
- sfx = (signed short *)sc->data + ch->pos;
+ sfx = (signed short *)sc->data; //@@@
for (i = 0; i < count; i++)
{
- data = sfx[i];
+ data = sfx[ch->pos >> 8]; //@@@
+
left = (data * leftvol) >> 8;
right = (data * rightvol) >> 8;
paintbuffer[i].left += left;
paintbuffer[i].right += right;
- }
- ch->pos += count;
+ //@@@
+ ch->pos += ch->step;
+ if ((ch->pos >> 8) >= sc->length) break;
+ }
}
- andrewj
- Posts: 133
- Joined: Mon Aug 30, 2010 3:29 pm
- Location: Australia
holy crap this rules just tried it thanks!
i've noticed on lower pitches the sound gets cut off slightly and on higher pitches, it kind of 'squeaks'. sc->length isn't being compensated
and there is a bit of low precision here... i'm trying with 256 + (rand()&16) and i can only make out two different pitch tones.
static sounds are also broken, but you can drop this at the end of S_StaticSound to fix them
Ambient sound (sky/water) still remains broken though
As for DUMB, it's very hard to integrate into the Quake DMA buffer. i'm still trying to do that for mod music playback (and ogg too)
i've noticed on lower pitches the sound gets cut off slightly and on higher pitches, it kind of 'squeaks'. sc->length isn't being compensated
and there is a bit of low precision here... i'm trying with 256 + (rand()&16) and i can only make out two different pitch tones.
static sounds are also broken, but you can drop this at the end of S_StaticSound to fix them
- Code: Select all
ss->step = 256;
Ambient sound (sky/water) still remains broken though
As for DUMB, it's very hard to integrate into the Quake DMA buffer. i'm still trying to do that for mod music playback (and ogg too)
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
fmod is irrelevant now and it doesn't support dos anyway and it doesn't even have good linux support either. i'd rather use allegro than fmod lol (but i am no longer using allegro since it does mean dirty things to quake's timing)
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
generic code time:
the code above doesn't compensate the end time for the time it starts/stops.
the 'end' time is in output sound samples
But if you make it play faster, you need to change the maths.
Where your old code has:
ch->end = panttime + newduration;
You need to insert this:
ch->end = painttime + ((newduration<<8)/ch->step);
Just scale the duration changes.
You'll need to make this change anywhere that the end can be set on a sound which has a custom rate. At a minimum, snd_mix.c can set the sound to start at an offset into a sound (newduraction is scache->length-scache->loopstart, and don't forget to scale the ch->pos there either).
the code above doesn't compensate the end time for the time it starts/stops.
the 'end' time is in output sound samples
But if you make it play faster, you need to change the maths.
Where your old code has:
ch->end = panttime + newduration;
You need to insert this:
ch->end = painttime + ((newduration<<8)/ch->step);
Just scale the duration changes.
You'll need to make this change anywhere that the end can be set on a sound which has a custom rate. At a minimum, snd_mix.c can set the sound to start at an offset into a sound (newduraction is scache->length-scache->loopstart, and don't forget to scale the ch->pos there either).
- Spike
- Posts: 2892
- Joined: Fri Nov 05, 2004 3:12 am
- Location: UK
andrewj wrote:
- Code: Select all
// !!! if this is changed, it much be changed in asm_i386.h too !!!
andrewj wrote:
- Code: Select all
+ int step;
int looping; // where to loop, -1 = no looping
int entnum; // to allow overriding a specific sound
int entchannel; //
vec3_t origin; // origin of sound effect
vec_t dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
} channel_t;
Inserting fields in the middle of structs containing this warning may result in errors in the assembly code, since the assembly code uses hard-coded offsets to find the memory addresses of struct fields. Due to this, the best place to add new fields is at the end of the structs, except in cases where the assembly code uses the total size of the struct for something, in which case there's no way to add anything to the struct without breaking compatibility with the original assembly code.
Of course, there's also the option of editing the assembly code to match any changes made to the C code.
-

mankrip - Posts: 915
- Joined: Fri Jul 04, 2008 3:02 am
11 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest
