1 /* aylet 0.3, a .AY music file player.
2  * Copyright (C) 2001-2002 Russell Marks and Ian Collier.
3  * See main.c for licence.
4  *
5  * sound.c - the sound emulation itself, based on the beeper/AY code I
6  *           wrote for Fuse.
7  */
8 
9 /* some AY details (volume levels, white noise RNG algorithm) based on
10  * info from MAME's ay8910.c - MAME's licence explicitly permits free
11  * use of info (even encourages it).
12  */
13 
14 /* NB: I know some of this stuff looks fairly CPU-hogging.
15  * For example, the AY code tracks changes with sub-frame timing
16  * in a rather hairy way, and there's subsampling here and there.
17  * But if you measure the CPU use, it doesn't actually seem
18  * very high at all. And I speak as a Cyrix owner. :-)
19  *
20  * (I based that on testing in Fuse, but I doubt it's that much
21  * worse here. (It's actually a bit better, I think.))
22  */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 
30 #include "main.h"
31 #include "z80.h"
32 
33 #include "sound.h"
34 #include "driver.h"
35 
36 /* configuration */
37 int soundfd=-1;			/* file descriptor for the sound device */
38 int sixteenbit=1;		/* use sixteen-bit audio? */
39 
40 int sound_enabled=0;
41 int sound_freq=44100;
42 int sound_stereo=1;		/* true for stereo *output sample* (only) */
43 int sound_stereo_beeper=0;	/* beeper pseudo-stereo */
44 int sound_stereo_ay=1;		/* AY stereo separation */
45 int sound_stereo_ay_abc=0;	/* (AY stereo) true for ABC stereo, else ACB */
46 int sound_stereo_ay_narrow=0;	/* (AY stereo) true for narrow AY st. sep. */
47 
48 
49 #define AY_CLOCK		1773400
50 #define AY_CLOCK_CPC		1000000
51 
52 
53 /* assume all three tone channels together match the beeper volume.
54  * (XXX maybe not - that makes beeper stuff annoyingly loud)
55  * Must be <=127 for all channels; 40+(28*3) = 124.
56  * (Now scaled up for 16-bit.)
57  */
58 #define AMPL_BEEPER		(40*256)
59 #define AMPL_AY_TONE		(28*256)	/* three of these */
60 
61 /* full range of beeper volume */
62 #define VOL_BEEPER		(AMPL_BEEPER*2)
63 
64 /* max. number of sub-frame AY port writes allowed;
65  * given the number of port writes theoretically possible in a
66  * 50th I think this should be plenty.
67  */
68 #define AY_CHANGE_MAX		8000
69 
70 static int sound_framesiz;
71 
72 static unsigned int ay_tone_levels[16];
73 
74 static signed short *sound_buf;
75 static int sound_oldpos,sound_fillpos,sound_oldval,sound_oldval_orig;
76 
77 /* foo_subcycles are fixed-point with low 16 bits as fractional part.
78  * The other bits count as the chip does.
79  */
80 static unsigned int ay_tone_tick[3],ay_tone_high[3],ay_noise_tick;
81 static unsigned int ay_tone_subcycles,ay_env_subcycles;
82 static unsigned int ay_env_internal_tick,ay_env_tick;
83 static unsigned int ay_tick_incr;
84 static unsigned int ay_tone_period[3],ay_noise_period,ay_env_period;
85 
86 static int beeper_last_subpos=0;
87 
88 /* AY registers */
89 /* we have 16 so we can fake an 8910 if needed (XXX any point?) */
90 static unsigned char sound_ay_registers[16];
91 
92 struct ay_change_tag
93   {
94   unsigned long tstates;
95   unsigned short ofs;
96   unsigned char reg,val;
97   };
98 
99 static struct ay_change_tag ay_change[AY_CHANGE_MAX];
100 static int ay_change_count;
101 
102 
103 static int fading=0,fadetotal;
104 static int sfadetime;
105 
106 #define STEREO_BUF_SIZE 1024
107 
108 static int pstereobuf[STEREO_BUF_SIZE];
109 static int pstereobufsiz,pstereopos;
110 static int psgap=250;
111 static int rstereobuf_l[STEREO_BUF_SIZE],rstereobuf_r[STEREO_BUF_SIZE];
112 static int rstereopos,rchan1pos,rchan2pos,rchan3pos;
113 
114 
115 
sound_ay_init(void)116 void sound_ay_init(void)
117 {
118 /* AY output doesn't match the claimed levels; these levels are based
119  * on the measurements posted to comp.sys.sinclair in Dec 2001 by
120  * Matthew Westcott, adjusted as I described in a followup to his post,
121  * then scaled to 0..0xffff.
122  */
123 static int levels[16]=
124   {
125   0x0000, 0x0385, 0x053D, 0x0770,
126   0x0AD7, 0x0FD5, 0x15B0, 0x230C,
127   0x2B4C, 0x43C1, 0x5A4B, 0x732F,
128   0x9204, 0xAFF1, 0xD921, 0xFFFF
129   };
130 int f;
131 
132 /* scale the values down to fit */
133 for(f=0;f<16;f++)
134   ay_tone_levels[f]=(levels[f]*AMPL_AY_TONE+0x8000)/0xffff;
135 
136 ay_noise_tick=ay_noise_period=0;
137 ay_env_internal_tick=ay_env_tick=ay_env_period=0;
138 ay_tone_subcycles=ay_env_subcycles=0;
139 for(f=0;f<3;f++)
140   ay_tone_tick[f]=ay_tone_high[f]=0,ay_tone_period[f]=1;
141 
142 #define CLOCK_RESET(clock) ay_tick_incr=(int)(65536.*clock/sound_freq)
143 
144 CLOCK_RESET(AY_CLOCK);
145 
146 ay_change_count=0;
147 }
148 
149 
sound_init(void)150 int sound_init(void)
151 {
152 int f;
153 
154 if(!driver_init(&sound_freq,&sound_stereo))
155   return(0);
156 
157 /* important to override these if not using stereo */
158 if(!sound_stereo)
159   {
160   sound_stereo_ay=0;
161   sound_stereo_beeper=0;
162   }
163 
164 sound_enabled=1;
165 sound_framesiz=sound_freq/50;
166 
167 if((sound_buf=malloc(sizeof(signed short)*sound_framesiz*(sound_stereo+1)))==NULL)
168   {
169   sound_end();
170   return(0);
171   }
172 
173 sound_oldval=sound_oldval_orig=0;
174 sound_oldpos=-1;
175 sound_fillpos=0;
176 
177 sound_ay_init();
178 
179 if(sound_stereo_beeper)
180   {
181   for(f=0;f<STEREO_BUF_SIZE;f++)
182     pstereobuf[f]=0;
183   pstereopos=0;
184   pstereobufsiz=(sound_freq*psgap)/22000;
185   }
186 
187 if(sound_stereo_ay)
188   {
189   int pos=(sound_stereo_ay_narrow?3:6)*sound_freq/8000;
190 
191   for(f=0;f<STEREO_BUF_SIZE;f++)
192     rstereobuf_l[f]=rstereobuf_r[f]=0;
193   rstereopos=0;
194 
195   /* the actual ACB/ABC bit :-) */
196   rchan1pos=-pos;
197   if(sound_stereo_ay_abc)
198     rchan2pos=0,  rchan3pos=pos;
199   else
200     rchan2pos=pos,rchan3pos=0;
201   }
202 
203 return(1);
204 }
205 
206 
sound_end(void)207 void sound_end(void)
208 {
209 if(sound_enabled)
210   {
211   if(sound_buf)
212     free(sound_buf);
213   driver_end();
214   sound_enabled=0;
215   }
216 }
217 
218 
219 /* write sample to buffer as pseudo-stereo */
sound_write_buf_pstereo(signed short * out,int c)220 void sound_write_buf_pstereo(signed short *out,int c)
221 {
222 int bl=(c-pstereobuf[pstereopos])/2;
223 int br=(c+pstereobuf[pstereopos])/2;
224 
225 if(bl<-AMPL_BEEPER) bl=-AMPL_BEEPER;
226 if(br<-AMPL_BEEPER) br=-AMPL_BEEPER;
227 if(bl> AMPL_BEEPER) bl= AMPL_BEEPER;
228 if(br> AMPL_BEEPER) br= AMPL_BEEPER;
229 
230 *out=bl; out[1]=br;
231 
232 pstereobuf[pstereopos]=c;
233 pstereopos++;
234 if(pstereopos>=pstereobufsiz)
235   pstereopos=0;
236 }
237 
238 
239 
240 /* not great having this as a macro to inline it, but it's only
241  * a fairly short routine, and it saves messing about.
242  * (XXX ummm, possibly not so true any more :-))
243  */
244 #define AY_GET_SUBVAL(chan)	(level*2*ay_tone_tick[chan]/tone_count)
245 
246 #define AY_DO_TONE(var,chan) \
247   is_low=0;								\
248   if(is_on)								\
249     {									\
250     (var)=0;								\
251     if(level)								\
252       {									\
253       if(ay_tone_high[chan])						\
254         (var)= (level);							\
255       else								\
256         (var)=-(level),is_low=1;					\
257       }									\
258     }									\
259   									\
260   ay_tone_tick[chan]+=tone_count;					\
261   count=0;								\
262   while(ay_tone_tick[chan]>=ay_tone_period[chan])			\
263     {									\
264     count++;								\
265     ay_tone_tick[chan]-=ay_tone_period[chan];				\
266     ay_tone_high[chan]=!ay_tone_high[chan];				\
267     									\
268     /* has to be here, unfortunately... */				\
269     if(is_on && count==1 && level && ay_tone_tick[chan]<tone_count)	\
270       {									\
271       if(is_low)							\
272         (var)+=AY_GET_SUBVAL(chan);					\
273       else								\
274         (var)-=AY_GET_SUBVAL(chan);					\
275       }									\
276     }									\
277   									\
278   /* if it's changed more than once during the sample, we can't */	\
279   /* represent it faithfully. So, just hope it's a sample.      */	\
280   /* (That said, this should also help avoid aliasing noise.)   */	\
281   if(is_on && count>1)							\
282     (var)=-(level)
283 
284 
285 /* add val, correctly delayed on either left or right buffer,
286  * to add the AY stereo positioning. This doesn't actually put
287  * anything directly in soundbuf, though.
288  */
289 #define GEN_STEREO(pos,val) \
290   if((pos)<0)							\
291     {								\
292     rstereobuf_l[rstereopos]+=(val);				\
293     rstereobuf_r[(rstereopos-pos)%STEREO_BUF_SIZE]+=(val);	\
294     }								\
295   else								\
296     {								\
297     rstereobuf_l[(rstereopos+pos)%STEREO_BUF_SIZE]+=(val);	\
298     rstereobuf_r[rstereopos]+=(val);				\
299     }
300 
301 
302 
303 /* bitmasks for envelope */
304 #define AY_ENV_CONT	8
305 #define AY_ENV_ATTACK	4
306 #define AY_ENV_ALT	2
307 #define AY_ENV_HOLD	1
308 
309 
sound_ay_overlay(void)310 static void sound_ay_overlay(void)
311 {
312 static int rng=1;
313 static int noise_toggle=0;
314 static int env_first=1,env_rev=0,env_counter=15;
315 int tone_level[3];
316 int mixer,envshape;
317 int f,g,level,count;
318 signed short *ptr;
319 struct ay_change_tag *change_ptr=ay_change;
320 int changes_left=ay_change_count;
321 int reg,r;
322 int is_low,is_on;
323 int chan1,chan2,chan3;
324 int frametime=tsmax*50;
325 unsigned int tone_count,noise_count;
326 
327 /* convert change times to sample offsets */
328 for(f=0;f<ay_change_count;f++)
329   ay_change[f].ofs=(ay_change[f].tstates*sound_freq)/frametime;
330 
331 for(f=0,ptr=sound_buf;f<sound_framesiz;f++)
332   {
333   /* update ay registers. All this sub-frame change stuff
334    * is pretty hairy, but how else would you handle the
335    * samples in Robocop? :-) It also clears up some other
336    * glitches.
337    */
338   while(changes_left && f>=change_ptr->ofs)
339     {
340     sound_ay_registers[reg=change_ptr->reg]=change_ptr->val;
341     change_ptr++; changes_left--;
342 
343     /* fix things as needed for some register changes */
344     switch(reg)
345       {
346       case 0: case 1: case 2: case 3: case 4: case 5:
347         r=reg>>1;
348         /* a zero-len period is the same as 1 */
349         ay_tone_period[r]=(sound_ay_registers[reg&~1]|
350                            (sound_ay_registers[reg|1]&15)<<8);
351         if(!ay_tone_period[r])
352           ay_tone_period[r]++;
353 
354         /* important to get this right, otherwise e.g. Ghouls 'n' Ghosts
355          * has really scratchy, horrible-sounding vibrato.
356          */
357         if(ay_tone_tick[r]>=ay_tone_period[r]*2)
358           ay_tone_tick[r]%=ay_tone_period[r]*2;
359         break;
360       case 6:
361         ay_noise_tick=0;
362         ay_noise_period=(sound_ay_registers[reg]&31);
363         break;
364       case 11: case 12:
365         /* this one *isn't* fixed-point */
366         ay_env_period=sound_ay_registers[11]|(sound_ay_registers[12]<<8);
367         break;
368       case 13:
369         ay_env_internal_tick=ay_env_tick=ay_env_subcycles=0;
370         env_first=1;
371         env_rev=0;
372         env_counter=(sound_ay_registers[13]&AY_ENV_ATTACK)?0:15;
373         break;
374       }
375     }
376 
377   /* the tone level if no enveloping is being used */
378   for(g=0;g<3;g++)
379     tone_level[g]=ay_tone_levels[sound_ay_registers[8+g]&15];
380 
381   /* envelope */
382   envshape=sound_ay_registers[13];
383   level=ay_tone_levels[env_counter];
384 
385   for(g=0;g<3;g++)
386     if(sound_ay_registers[8+g]&16)
387       tone_level[g]=level;
388 
389   /* envelope output counter gets incr'd every 16 AY cycles.
390    * Has to be a while, as this is sub-output-sample res.
391    */
392   ay_env_subcycles+=ay_tick_incr;
393   noise_count=0;
394   while(ay_env_subcycles>=(16<<16))
395     {
396     ay_env_subcycles-=(16<<16);
397     noise_count++;
398     ay_env_tick++;
399     while(ay_env_tick>=ay_env_period)
400       {
401       ay_env_tick-=ay_env_period;
402 
403       /* do a 1/16th-of-period incr/decr if needed */
404       if(env_first ||
405          ((envshape&AY_ENV_CONT) && !(envshape&AY_ENV_HOLD)))
406         {
407         if(env_rev)
408           env_counter-=(envshape&AY_ENV_ATTACK)?1:-1;
409         else
410           env_counter+=(envshape&AY_ENV_ATTACK)?1:-1;
411         if(env_counter<0) env_counter=0;
412         if(env_counter>15) env_counter=15;
413         }
414 
415       ay_env_internal_tick++;
416       while(ay_env_internal_tick>=16)
417         {
418         ay_env_internal_tick-=16;
419 
420         /* end of cycle */
421         if(!(envshape&AY_ENV_CONT))
422           env_counter=0;
423         else
424           {
425           if(envshape&AY_ENV_HOLD)
426             {
427             if(env_first && (envshape&AY_ENV_ALT))
428               env_counter=(env_counter?0:15);
429             }
430           else
431             {
432             /* non-hold */
433             if(envshape&AY_ENV_ALT)
434               env_rev=!env_rev;
435             else
436               env_counter=(envshape&AY_ENV_ATTACK)?0:15;
437             }
438           }
439 
440         env_first=0;
441         }
442 
443       /* don't keep trying if period is zero */
444       if(!ay_env_period) break;
445       }
446     }
447 
448   /* generate tone+noise... or neither.
449    * (if no tone/noise is selected, the chip just shoves the
450    * level out unmodified. This is used by some sample-playing
451    * stuff.)
452    */
453   chan1=tone_level[0];
454   chan2=tone_level[1];
455   chan3=tone_level[2];
456   mixer=sound_ay_registers[7];
457 
458   ay_tone_subcycles+=ay_tick_incr;
459   tone_count=ay_tone_subcycles>>(3+16);
460   ay_tone_subcycles&=(8<<16)-1;
461 
462   level=chan1; is_on=!(mixer&1);
463   AY_DO_TONE(chan1,0);
464   if((mixer&0x08)==0 && noise_toggle)
465     chan1=0;
466 
467   level=chan2; is_on=!(mixer&2);
468   AY_DO_TONE(chan2,1);
469   if((mixer&0x10)==0 && noise_toggle)
470     chan2=0;
471 
472   level=chan3; is_on=!(mixer&4);
473   AY_DO_TONE(chan3,2);
474   if((mixer&0x20)==0 && noise_toggle)
475     chan3=0;
476 
477   /* write the sample(s) */
478   if(!sound_stereo)
479     {
480     /* mono */
481     (*ptr++)+=chan1+chan2+chan3;
482     }
483   else
484     {
485     if(!sound_stereo_ay)
486       {
487       /* stereo output, but mono AY sound; still,
488        * incr separately in case of beeper pseudostereo.
489        */
490       (*ptr++)+=chan1+chan2+chan3;
491       (*ptr++)+=chan1+chan2+chan3;
492       }
493     else
494       {
495       /* stereo with ACB AY positioning.
496        * Here we use real stereo positions for the channels.
497        * Just because, y'know, it's cool and stuff. No, really. :-)
498        * This is a little tricky, as it works by delaying sounds
499        * on the left or right channels to model the delay you get
500        * in the real world when sounds originate at different places.
501        */
502       GEN_STEREO(rchan1pos,chan1);
503       GEN_STEREO(rchan2pos,chan2);
504       GEN_STEREO(rchan3pos,chan3);
505       (*ptr++)+=rstereobuf_l[rstereopos];
506       (*ptr++)+=rstereobuf_r[rstereopos];
507       rstereobuf_l[rstereopos]=rstereobuf_r[rstereopos]=0;
508       rstereopos++;
509       if(rstereopos>=STEREO_BUF_SIZE)
510         rstereopos=0;
511       }
512     }
513 
514   /* update noise RNG/filter */
515   ay_noise_tick+=noise_count;
516   while(ay_noise_tick>=ay_noise_period)
517     {
518     ay_noise_tick-=ay_noise_period;
519 
520     if((rng&1)^((rng&2)?1:0))
521       noise_toggle=!noise_toggle;
522 
523     /* rng is 17-bit shift reg, bit 0 is output.
524      * input is bit 0 xor bit 2.
525      */
526     rng|=((rng&1)^((rng&4)?1:0))?0x20000:0;
527     rng>>=1;
528 
529     /* don't keep trying if period is zero */
530     if(!ay_noise_period) break;
531     }
532   }
533 }
534 
535 
536 /* don't make the change immediately; record it for later,
537  * to be made by sound_frame() (via sound_ay_overlay()).
538  */
sound_ay_write(int reg,int val,unsigned long tstates)539 void sound_ay_write(int reg,int val,unsigned long tstates)
540 {
541 if(!sound_enabled) return;
542 
543 if(reg>=15) return;
544 
545 if(ay_change_count<AY_CHANGE_MAX)
546   {
547   ay_change[ay_change_count].tstates=tstates;
548   ay_change[ay_change_count].reg=reg;
549   ay_change[ay_change_count].val=val;
550   ay_change_count++;
551   }
552 }
553 
554 
555 /* no need to call this initially, but should be called
556  * on reset otherwise.
557  */
sound_ay_reset(void)558 void sound_ay_reset(void)
559 {
560 int f;
561 
562 ay_change_count=0;
563 for(f=0;f<16;f++)
564   sound_ay_write(f,0,0);
565 for(f=0;f<3;f++)
566   ay_tone_high[f]=0;
567 ay_tone_subcycles=ay_env_subcycles=0;
568 fading=sfadetime=0;
569 sound_oldval=sound_oldval_orig=0;
570 
571 CLOCK_RESET(AY_CLOCK);	/* in case it was CPC before */
572 }
573 
574 
sound_ay_reset_cpc(void)575 void sound_ay_reset_cpc(void)
576 {
577 sound_ay_reset();
578 
579 CLOCK_RESET(AY_CLOCK_CPC);
580 }
581 
582 
583 /* write stereo or mono beeper sample, and incr ptr */
584 #define SOUND_WRITE_BUF_BEEPER(ptr,val) \
585   do						\
586     {						\
587     if(sound_stereo_beeper)			\
588       {						\
589       sound_write_buf_pstereo((ptr),(val));	\
590       (ptr)+=2;					\
591       }						\
592     else					\
593       {						\
594       *(ptr)++=(val);				\
595       if(sound_stereo)				\
596         *(ptr)++=(val);				\
597       }						\
598     }						\
599   while(0)
600 
601 
602 /* returns zero if this frame was completely silent */
sound_frame(int really_play)603 int sound_frame(int really_play)
604 {
605 static int silent_level=-1;
606 signed short *ptr;
607 int f,silent,chk;
608 int fulllen=sound_framesiz*(sound_stereo+1);
609 
610 ptr=sound_buf+(sound_stereo?sound_fillpos*2:sound_fillpos);
611 for(f=sound_fillpos;f<sound_framesiz;f++)
612   SOUND_WRITE_BUF_BEEPER(ptr,sound_oldval);
613 
614 sound_ay_overlay();
615 
616 /* check for a silent frame.
617  * bit nasty, but it's the only way to be sure. :-)
618  * We check pre-fade, and make a separate check for having faded-out
619  * later. This is to avoid problems with beeper `silence' which is
620  * really a constant high/low level (something similar is also
621  * possible with the AY).
622  *
623  * To cope with beeper and arguably-buggy .ay files, we have to treat
624  * *any* non-varying level as silence. Fair enough in a way, as it
625  * will indeed be silent, but a bit of a pain.
626  */
627 silent=1;
628 ptr=sound_buf;
629 chk=*ptr++;
630 for(f=1;f<fulllen;f++)
631   {
632   if(*ptr++!=chk)
633     {
634     silent=0;
635     break;
636     }
637   }
638 
639 /* even if they're all the same, it doesn't count if the
640  * level's changed since last time...
641  */
642 if(chk!=silent_level)
643   silent=0;
644 
645 /* save last sample for comparison next time */
646 silent_level=sound_buf[fulllen-1];
647 
648 /* apply overall fade if we're in the middle of one. */
649 if(fading)
650   {
651   if(sfadetime<=0)
652     memset(sound_buf,0,fulllen*sizeof(signed short)),silent=1;
653   else
654     {
655     ptr=sound_buf;
656     for(f=0;f<sound_framesiz;f++,ptr++)
657       {
658       /* XXX kludgey, but needed to avoid overflow */
659       sfadetime--;
660       *ptr=(*ptr)*(sfadetime>>4)/(fadetotal>>4);
661       if(sound_stereo)
662         {
663         ptr++;
664         *ptr=(*ptr)*(sfadetime>>4)/(fadetotal>>4);
665         }
666       }
667     }
668   }
669 
670 if(really_play)
671   driver_frame(sound_buf,fulllen);
672 
673 sound_oldpos=-1;
674 sound_fillpos=0;
675 
676 ay_change_count=0;
677 
678 return(!silent);
679 }
680 
681 
682 /* don't do a real frame, just play silence to keep things sane. */
sound_frame_blank(void)683 void sound_frame_blank(void)
684 {
685 static int first=1;
686 static signed short buf[2048];		/* should be plenty */
687 int fulllen=sound_framesiz*(sound_stereo+1);
688 
689 if(first)
690   {
691   first=0;
692   memset(buf,0,sizeof(buf));
693   }
694 
695 /* just in case it's *not* plenty... :-) */
696 if(sizeof(buf)<fulllen)
697   {
698   usleep(20000);
699   return;
700   }
701 
702 driver_frame(buf,fulllen);
703 }
704 
705 
sound_start_fade(int fadetime_in_sec)706 void sound_start_fade(int fadetime_in_sec)
707 {
708 fading=1;
709 sfadetime=fadetotal=fadetime_in_sec*sound_freq;
710 }
711 
712 
sound_beeper(int on)713 void sound_beeper(int on)
714 {
715 signed short *ptr;
716 int newpos;
717 int subpos;
718 int val,subval;
719 int f;
720 
721 if(!sound_enabled) return;
722 
723 val=(on?-AMPL_BEEPER:AMPL_BEEPER);
724 
725 if(val==sound_oldval_orig) return;
726 
727 /* XXX a lookup table might help here... */
728 newpos=(tstates*sound_framesiz)/tsmax;
729 /* XXX long long may be dodgy portability-wise... */
730 subpos=(((long long)tstates)*sound_framesiz*VOL_BEEPER)/tsmax-VOL_BEEPER*newpos;
731 
732 /* if we already wrote here, adjust the level.
733  */
734 if(newpos==sound_oldpos)
735   {
736   /* adjust it as if the rest of the sample period were all in
737    * the new state. (Often it will be, but if not, we'll fix
738    * it later by doing this again.)
739    */
740   if(on)
741     beeper_last_subpos+=VOL_BEEPER-subpos;
742   else
743     beeper_last_subpos-=VOL_BEEPER-subpos;
744   }
745 else
746   beeper_last_subpos=(on?VOL_BEEPER-subpos:subpos);
747 
748 subval=AMPL_BEEPER-beeper_last_subpos;
749 
750 if(newpos>=0)
751   {
752   /* fill gap from previous position */
753   ptr=sound_buf+(sound_stereo?sound_fillpos*2:sound_fillpos);
754   for(f=sound_fillpos;f<newpos && f<sound_framesiz;f++)
755     SOUND_WRITE_BUF_BEEPER(ptr,sound_oldval);
756 
757   if(newpos<sound_framesiz)
758     {
759     /* newpos may be less than sound_fillpos, so... */
760     ptr=sound_buf+(sound_stereo?newpos*2:newpos);
761 
762     /* write subsample value */
763     SOUND_WRITE_BUF_BEEPER(ptr,subval);
764     }
765   }
766 
767 sound_oldpos=newpos;
768 sound_fillpos=newpos+1;
769 sound_oldval=sound_oldval_orig=val;
770 }
771