#definePCSPK_BUF_LEN1792#definePCSPK_SAMPLE_RATE32000#definePCSPK_MAX_FREQ(PCSPK_SAMPLE_RATE>>1)#definePCSPK_MIN_COUNT((PIT_FREQ+PCSPK_MAX_FREQ-1)/PCSPK_MAX_FREQ)typedefstruct{uint8_tsample_buf[PCSPK_BUF_LEN];QEMUSoundCardcard;SWVoiceOut*voice;PITState*pit;unsignedintpit_count;unsignedintsamples;unsignedintplay_pos;intdata_on;intdummy_refresh_clock;}PCSpkState;staticconstchar*s_spk="pcspk";staticPCSpkStatepcspk_state;staticinlinevoidgenerate_samples(PCSpkState*s){unsignedinti;if(s->pit_count){constuint32_tm=PCSPK_SAMPLE_RATE*s->pit_count;constuint32_tn=((uint64_t)PIT_FREQ<<32)/m;/* multiple of wavelength for gapless looping */s->samples=(PCSPK_BUF_LEN*PIT_FREQ/m*m/(PIT_FREQ>>1)+1)>>1;for(i=0;i<s->samples;++i)s->sample_buf[i]=(64&(n*i>>25))-32;}else{s->samples=PCSPK_BUF_LEN;for(i=0;i<PCSPK_BUF_LEN;++i)s->sample_buf[i]=128;/* silence */}}staticvoidpcspk_callback(void*opaque,intfree){PCSpkState*s=opaque;unsignedintn;if(pit_get_mode(s->pit,2)!=3)return;n=pit_get_initial_count(s->pit,2);/* avoid frequencies that are not reproducible with sample rate */if(n<PCSPK_MIN_COUNT)n=0;if(s->pit_count!=n){s->pit_count=n;s->play_pos=0;generate_samples(s);}while(free>0){n=audio_MIN(s->samples-s->play_pos,(unsignedint)free);n=AUD_write(s->voice,&s->sample_buf[s->play_pos],n);if(!n)break;s->play_pos=(s->play_pos+n)%s->samples;free-=n;}}
if(!s->voice){AUD_log(s_spk,"Could not open voice\n");return-1;}return0;}staticuint32_tpcspk_ioport_read(void*opaque,uint32_taddr){PCSpkState*s=opaque;intout;s->dummy_refresh_clock^=(1<<4);out=pit_get_out(s->pit,2,qemu_get_clock(vm_clock))<<5;returnpit_get_gate(s->pit,2)|(s->data_on<<1)|s->dummy_refresh_clock|out;}staticvoidpcspk_ioport_write(void*opaque,uint32_taddr,uint32_tval){PCSpkState*s=opaque;constintgate=val&1;s->data_on=(val>>1)&1;pit_set_gate(s->pit,2,gate);if(s->voice){if(gate)/* restart */s->play_pos=0;AUD_set_active_out(s->voice,gate&s->data_on);}}voidpcspk_init(PITState*pit){PCSpkState*s=&pcspk_state;s->pit=pit;register_ioport_read(0x61,1,1,pcspk_ioport_read,s);register_ioport_write(0x61,1,1,pcspk_ioport_write,s);}