// Project: FLDEVOX by Xaby // Created: 2017-04-06 /* converted from C to AGK2 by Xaby aka Folker Linstedt // Source: http://faculty.salina.k-state.edu/tim/software/vox/vox.html#the-standard // by Tim Bower /* File: adpcm.c Description: Routines to convert 12 bit linear samples to the Dialogic or Oki ADPCM coding format. I copied the algorithms out of the book "PC Telephony - The complete guide to designing, building and programming systems using Dialogic and Related Hardware" by Bob Edgar. pg 272-276. Note: Edgar's book says that the second to last value is 1408; however, * The standard says it is 1411. * Changed on 1/17/2003. */ // show all errors SetErrorMode(2) // set window properties SetWindowTitle( "FLDEVOX" ) SetWindowSize( 320, 200, 0 ) // set display properties SetVirtualResolution( 320, 200 ) SetOrientationAllowed( 1, 1, 1, 1 ) SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts Type adpcm_status last as integer // short -127..128 step_index as integer // short -127..128 EndType Global coder_stat as adpcm_status // global, because no classes? Function adpcm_init( stat as adpcm_status) stat.last = 0 stat.step_index = 0 coder_stat.last = 0 // only here because of global variable coder_stat.step_index = 0 // only here because of global variable EndFunction Global adpcm_step_size as integer[49] = [16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552] Function step_adjust(code as integer) value = 0 select( code && 0x07 ) case 0x00: value=-1 endcase case 0x01: value=-1 endcase case 0x02: value=-1 endcase case 0x03: value=-1 endcase case 0x04: value=2 endcase case 0x05: value=4 endcase case 0x06: value=6 endcase case 0x07: value=8 endcase endselect Endfunction value /* * Decode Linear to ADPCM */ function adpcm_decode( code as integer) // without global: function adpcm_decode( code as integer, stat as adpcm_status) diff as integer E as integer SS as integer samp as integer /* printf( "%x\t", code ); */ SS = adpcm_step_size[coder_stat.step_index] // stat.step_index without global E = SS/8 if ( code && 0x01 ) E = E+SS/4 endif if ( code && 0x02 ) E =E+ SS/2 endif if ( code && 0x04 ) E = E+SS endif // diff = (code & 0x08) ? -E : E; if (code && 0x08) > 0 // maybe =1 ? diff = -E else diff = E endif samp = coder_stat.last + diff // stat.last instead of coder_stat without global /* * Clip the values to +(2^11)-1 to -2^11. (12 bits 2's * compelement) * Note: previous version errantly clipped at +2048, which could * cause a 2's complement overflow and was likely the source of * clipping problems in the previous version. Thanks to Frank * van Dijk for the correction. TLB 3/30/04 */ if( samp > 2047 ) samp = 2047 endif if( samp < -2048 ) samp = -2048 endif coder_stat.last = samp // changed stat to coder_stat, because of *Pointer reference don't know how coder_stat.step_index = coder_stat.step_index + step_adjust( code ) if( coder_stat.step_index < 0 ) : coder_stat.step_index = 0 : endif if( coder_stat.step_index > 48 ) : coder_stat.step_index = 48 : endif // how does stat will be returned? // because of that, or the variable would not be set directly, I decided to make coder_stat global Endfunction samp Function LoadSoundVOX(filename$,frequenz) Channels = 1 Bits = 16 // Mono, 16 Bit adpcm_init( coder_stat ) // it's global, don't know, how to make a reference pointer *coder_stat SoundID = -1 adpcmem = CreateMemblockFromFile(filename$) // vox without header RAW 4 Bit // 1 Byte contains 2 Samples. "1 Byte contains 4 Bytes" mox = CreateMemblock(GetMemblockSize(adpcmem)*4+12) // +12 for Header SetMemblockByte(mox,0,Channels) // mono SetMemblockByte(mox,2,Bits) // 16 Bit SetMemblockInt (mox,4,frequenz) // 44100 SetMemblockInt (mox,8,GetMemblockSize(adpcmem)*2) // 4 // buffer12 is mox for i=0 to GetMemblockSize(adpcmem)-1 SetMemblockShort(mox,12+i*4+0,adpcm_decode( (GetMemblockByte(adpcmem,i)>>4)&&0x0f )*16) SetMemblockShort(mox,12+i*4+2,adpcm_decode( GetMemblockByte(adpcmem,i)&&0x0f )*16) Next //--- create SoundHeader --- soundID = CreateSoundFromMemblock(mox) // was for test only, is not a real WAVE-RIFF File, but works in AudaCity as RAW CreateFileFromMemblock("_testfile_44100_16Bit_Mono.raw",mox) DeleteMemblock(mox) DeleteMemblock(adpcmem) EndFunction soundID voxid = LoadSoundVOX("woman_16-bit_44KHz_master.vox",44100) // Mono Only supported, but could be changed easily If voxid <> -1 PlaySound(voxid) EndIf do Print( "DeVOX, plays VOX-Files, ADPCM 4 Bit converts to 16 Bit FPS: "+Str(ScreenFPS(),2) ) Print(voxid) Sync() loop