Forum

Variable sound frequency/rate/speed changing

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Variable sound frequency/rate/speed changing

Postby leileilol » Tue Nov 02, 2010 4:11 pm

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?
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Postby andrewj » Wed Nov 03, 2010 1:34 am

Yeah the "right" way is to rework the painting code to support fractional stepping through the sound data.

I'll have a crack at it later tonight.....
andrewj
 
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Postby leileilol » Wed Nov 03, 2010 2:39 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...
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Postby andrewj » Wed Nov 03, 2010 8:13 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 :P

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

Postby leileilol » Wed Nov 03, 2010 8:24 am

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

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

Postby mh » Wed Nov 03, 2010 10:12 am

I believe that if you switch to GPL3 FMOD shouldn't present any problems.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby leileilol » Wed Nov 03, 2010 10:16 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

Postby Spike » Sat Nov 06, 2010 8:12 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).
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby leileilol » Sat Nov 06, 2010 9:29 am

that works. wth is a panttime duraction though
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Postby mankrip » Wed Nov 10, 2010 6:06 am

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.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am

Postby leileilol » Wed Nov 10, 2010 9:36 am

yeah, with abrash's crazy asm work itll take an act of god to pull that off.
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am


Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest