with calendar; with rtext_io; package body voc_pc is procedure halve(voice_block : in out voice_blocks; automatic_gain_control : in boolean:=true) is function "="(left,right:in voc_data.block_types) return boolean renames voc_data."="; function "="(left,right:in voc_data.pack_types) return boolean renames voc_data."="; -- how long to wait before turning volume louder or softer turn_louder_lag:constant duration:=0.2; -- be slow to turn up turn_softer_lag:constant duration:=0.02; -- but fast to turn down a,b:integer; err:integer:=0; subtype multiplier_range is integer range 4 .. 32; multiplier:multiplier_range:=8; -- starting multiplier volume_adjustment_point:constant integer :=integer(voice_block.sample_rate*turn_louder_lag); too_loud_delta:constant integer :=integer(turn_louder_lag/turn_softer_lag); error_level:integer:=0; j:integer:=1; begin if voice_block.packing /= voc_data.unpacked then return;end if; voice_block.packing:=voc_data.halved; voice_block.block_length:=(voice_block.block_length-1)/2; for i in 1 .. voice_block.block_length loop a:=(integer(voice_block.data(j+1))-integer(voice_block.data(j))) *multiplier+128+err; if a < 0 then err:=a;a:=0; error_level:=error_level+too_loud_delta; elsif a > 255 then err:=a-255;a:=255; error_level:=error_level+too_loud_delta; else error_level:=error_level-1; err:=0; end if; j:=j+1; b:=(integer(voice_block.data(j+1))-integer(voice_block.data(j))) *multiplier+128+err; if b < 0 then err:=b;b:=0; error_level:=error_level+too_loud_delta; elsif b > 255 then err:=b-255;b:=255; error_level:=error_level+too_loud_delta; else error_level:=error_level-1; err:=0; end if; j:=j+1; if automatic_gain_control then if error_level >= volume_adjustment_point then if multiplier > multiplier_range'first then multiplier:=multiplier-1; end if; error_level:=0; elsif error_level <= -volume_adjustment_point then if multiplier < multiplier_range'last then multiplier:=multiplier+1; end if; error_level:=0; end if; else error_level:=0; end if; a:=(a+7)/16; b:=(b+7)/16; if a > 15 then a:=15;end if; if b > 15 then b:=15;end if; if a < 8 then a:=15-a;else a:=a-8;end if; if b < 8 then b:=15-b;else b:=b-8;end if; voice_block.data(i):=voc_data.sound_bytes(a*16+b); end loop; end halve; procedure play(voc_block:in out VOC_data.blocks) is function "="(left,right:in voc_data.block_types) return boolean renames voc_data."="; function "="(left,right:in voc_data.pack_types) return boolean renames voc_data."="; begin if voc_block.block_type = voc_data.silence then declare -- poll for key press for appropriate duration use calendar; time_to_stop:constant calendar.time :=calendar.clock+voc_block.silence_interval; begin while calendar.clock < time_to_stop loop exit when rtext_io.keypress; end loop; end; return; end if; if voc_block.block_type /= voc_data.voice_data then return; end if; pc_sound.set_sample_rate(voc_block.sample_rate); if voc_block.packing=voc_data.unpacked then halve(voc_block); end if; -- other packing styles may generate gibberish pc_sound.playback(voc_block.data(1)'address,voc_block.block_length); end play; end voc_pc;