Bob Ammerman wrote:
Here is my understanding so far, expressed in C-like pseudocode: FULL_SCALE = the highest valid sample value MIN_DELTA = a constant MAX_DELTA = another constant cur_delta = MIN_DELTA; cur_value = FULL_SCALE / 2; // Current output value for (;;) // loop as long as we have samples to encode { // see if we are in a slope overload condition if (last 3 bits have all been 0's or all been 1's) overload = 1; else overload = 0; // given our current delta, and whether we are in a slope // overload, compute our new delta. This will probably be done // via lookup in a precomputed table. The function implemented // is an exponential (ie: like a capacitor charge/discharge curve) // limited at MIN_DELTA and MAX_DELTA. We 'charge' the cap // when overload is 1 and 'discharge' when overload is 0. cur_delta = compute_new_delta(cur_delta, overload); // adjust the output value in the correct direction if (input_value > cur_value) { output a 1; cur_value += cur_delta; if (cur_value > FULL_SCALE) cur_value = FULL_SCALE; } else { output a 0; cur_value -= cur_delta; if (cur_value < 0) cur_value = 0 } }
Richard Ottosen says:
I fired up my old Apple ][ (that's an oxymoron) and pulled off the CVSD files. I have attached them in a zip file. Use them at your own risk since I haven't looked at them in a dozen years. They are in a slightly unusual (for the 6502 microprocessor) assembler syntax.;ECHOCVSD.P65 ;THIS PROGRAM WILL INPUT SOUNDS FROM ;AN A/D AND OUTPUT THOSE SOUNDS TO THE ;THE D/A. ;A MOUNTAIN HARDWARE A/D+D/A CARD IS ;EXPECTED TO BE IN SLOT 5. ;THE DATA IS CONTINUOUS VARIABLE SLOPE ;DELTA (CVSD) MODULATED AND DEMODULATED ;BEFORE OUTPUTTING. THERE IS ABOUT 37K ;BYTES OF STORAGE. THE DATA IS PACKED ;8 BITS PER BYTE. ;DEFINE WHERE THE A/D AND D/A CONVERTORS ;ARE AT .DEF A2D0=$C0D0 ;A/D CHANNEL 0 .DEF D2A0=$C0D0 ;D/A CHANNEL 0 ;DEFINE TOP OF BUFFER MEMORY .DEF BUFFEND=$A0 ;TOP PAGE OF BUFFER +1 .LOC $56 PTR: .WORD ;FOR ADDRESSING THE BUFFER DIR: .BYTE ;DIRECTION OF INTEGRATION ;CARRY CLEAR FOR UP, CARRY SET ; FOR DOWN ;MODULATOR VARIABLES MSLOPE: .BYTE ;SLOPE OF INTEGRATION MINT: .BYTE ;INTERGRATOR MSHIFT: .BYTE ;ALGORITHM SHIFT REGISTER MTEMP: .BYTE ;DEMODULATOR VARIABLES DSLOPE: .BYTE ;SLOPE OF INTEGRATION DINT: .BYTE ;INTERGRATOR DSHIFT: .BYTE ;ALGORITHM SHIFT REGISTER DTEMP: .BYTE .LOC $800 START: DMOV# $1000,PTR ;INIT POINTER FOR BUFFER LDY# 0 ; Y TOO LDA# 128 ;INIT INTEGRATORS TO CENTER STA MINT STA DINT LDA# 1 STA MSLOPE ;INIT TO A CONSTANT SLOPE STA DSLOPE LDA# $55 ;SET FOR NO SLOPE INTEGRATION STA MSHIFT STA DSHIFT LOOP: LDX# 8 ;8 BITS PACKED PER BYTE M05: LDA MINT ;GET INTEGRATOR AND A2D INPUT CMP A2D0 ;IS THE INPUT LARGER THAN THE BCS M30 ; LAST VALUE INTEGRATED TO? M10: ADC MSLOPE ;IF SO, ADD A SLOPE INCREMENT BCC M100 LDA# 255 M20: CLC ;INDICATE POSITIVE SLOPE BCC M100 M30: SBC MSLOPE ; SUBTRACT THE SLOPE BCS M100 LDA# 0 M40: SEC ;INDICATE NEGATIVE SLOPE M100: STA MINT ROL MSHIFT ;PUT DIR IN SHIFT REG. LDA MSHIFT AND# 7 ;DO 3 BIT ALGORITHM BEQ M250 CMP# 7 BEQ M250 DEC MSLOPE BNE M300 ;DON'T LET SLOPE GO NEGATIVE ;NOTE: EVEN 0 MAY NOT BE DESIRABLE M250: INC MSLOPE M300: DEX ;BYTE PACKED FULL YET? BNE M05 LDA MSHIFT STA@Y PTR ;STORE BYTE IN BUFFER INY ;INC POINTER AND BNE LOOP INC PTR +1 LDA# BUFFEND ;ARE WE PAST TOP PAGE OF BUFFER? CMP PTR +1 BNE LOOP ;ECHO IT LOOP3: DMOV# $1000,PTR LOOP2: LDX# 8 ;8 PACKED BITS PER BYTE LDA@Y PTR ;SIG:=SIG +/- SLOPE STA DIR D05: LDA DINT ROL DIR BCS D30 ; LAST VALUE INTEGRATED TO? D10: ADC DSLOPE ;IF SO, ADD A SLOPE INCREMENT BCC D100 LDA# 255 D20: CLC ;INDICATE POSITIVE SLOPE BCC D100 D30: SBC DSLOPE ; SUBTRACT THE SLOPE BCS D100 LDA# 0 D40: SEC ;INDICATE NEGATIVE SLOPE D100: STA DINT ;SAVE INTO INTEGRATOR STA D2A0 ;OUTPUT IT ROL DSHIFT ;PUT DIR IN SHIFT REG. LDA DSHIFT AND# 7 ;DO 3 BIT ALGORITHM BEQ D250 CMP# 7 BEQ D250 DEC DSLOPE BNE D300 ;DON'T LET SLOPE GO NEGATIVE ;NOTE: EVEN 0 MAY NOT BE DESIRABLE D250: INC DSLOPE D300: DEX ;BYTE UNPACKED YET? BNE D05 INY BNE LOOP2 INC PTR +1 LDA# BUFFEND CMP PTR +1 BNE LOOP2 JMP START ;DO FOREVER .END
See also:
Questions: