⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmadpcm.pas

📁 一套及时通讯的原码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
   { sample and multiply that with dwDecoded...                        }

adpcmDecode4BitExit:
   Result := (dwDecoded * ((bBitsPerSample div 8) * bChannels));
end;

{==============================================================================}
function adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2, iP5, iP4, iP3, iP2, iP1: Smallint): Smallint;
var
   lTotal: Longint;
   lTemp : Longint;

begin
   { use average of 3 predictions }
   lTemp  := ((Longint(iP5) * iCoef2) + (Longint(iP4) * iCoef1)) shr MSADPCM_CSCALE;
   if (lTemp > iP3) then
      lTotal := lTemp - iP3
   else
      lTotal := iP3 - lTemp;

   lTemp  := ((Longint(iP4) * iCoef2) + (Longint(iP3) * iCoef1)) shr MSADPCM_CSCALE;
   if (lTemp > iP2) then
      lTotal := lTotal + (lTemp - iP2)
   else
      lTotal := lTotal + (iP2 - lTemp);

   lTemp  := ((Longint(iP3) * iCoef2) + (Longint(iP2) * iCoef1)) shr MSADPCM_CSCALE;
   if (lTemp > iP1) then
      lTotal := lTotal + (lTemp - iP1)
   else
      lTotal := lTotal + (iP1 - lTemp);

   { optimal iDelta is 1/4 of prediction error }
   Result := lTotal div 12;
   if (Result < MSADPCM_DELTA4_MIN) then
       Result := MSADPCM_DELTA4_MIN;
end;

const
     ENCODE_DELTA_LOOKAHEAD = 5;

{==============================================================================}
function adpcmEncode4Bit(lpwfPCM: PWaveFormatEx; lpwfADPCM: PADPCMWaveFormat;
                         pSrc: PChar; pDst: PChar; dwSrcLen: DWORD): DWORD;
var
   lpSamplesBuf, lpSamples: Pchar;

    abBestPredictor: array[0..MSADPCM_MAX_CHANNELS-1] of Byte;

    adwTotalError: array[0..MSADPCM_NUM_COEF-1,0..MSADPCM_MAX_CHANNELS-1] of DWORD;

    aiSamples: array[0..ENCODE_DELTA_LOOKAHEAD-1,0..MSADPCM_MAX_CHANNELS-1] of Smallint;
    aiFirstDelta: array[0..MSADPCM_NUM_COEF-1,0..MSADPCM_MAX_CHANNELS-1] of Smallint;
    aiDelta: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
    aiSamp1: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;
    aiSamp2: array[0..MSADPCM_MAX_CHANNELS-1] of Smallint;

    iCoef1,iCoef2,iSamp1,iSamp2,iDelta,iSample,iOutput: Smallint;

    lSamp: Longint;

    dw,dwTotalConverted,dwInputPos: DWORD;

    lError,lPrediction: Longint;

    wSamplesPerBlock,
    cbSample,
    wBlockHeaderBytes,
    wBlockSize,
    wNextWrite,
    wFirstNibble,
    n: Word;

    m,
    i,
    bChannels,
    bBitsPerSample: Byte;

begin
   { first copy some information into more accessible (cheaper and shorter) }
   { variables--and precompute some stuff...                                }
   wSamplesPerBlock    := lpwfADPCM^.wSamplesPerBlock;
   bChannels           := lpwfPCM^.nChannels;
   bBitsPerSample      := lpwfPCM^.wBitsPerSample;
   wBlockHeaderBytes   := bChannels * 7;
   dwInputPos          := 0;
   dwTotalConverted    := 0;

   { calculate the number of bytes per sample in the PCM data            }
   {                                                                     }
   { note: the following code works because we _know_ that we only deal  }
   { with 8 or 16 bits per sample PCM and 1 or 2 channels..              }

   cbSample := (bBitsPerSample div 8) * bChannels;

   { we allocate and use a small buffer (<64k) to hold an entire block of }
   { samples to be encoded. the reason for this is mainly because we      }
   { make 8 passes over the data per block and using huge pointers all    }
   { of the time is expensive. so we put it in a <64k chunk and eliminate }
   { the huge pointer stuff                                               }

   lpSamplesBuf := GlobalAllocPtr(GMEM_MOVEABLE or GMEM_SHARE, wSamplesPerBlock * cbSample);
   if (lpSamplesBuf = nil) then
   begin
      Result := 0;
      exit;
   end;

   { step through each block of PCM data and encode it to 4 bit ADPCM }

   while dwInputPos < dwSrcLen do
   begin
      { determine how much data we should encode for this block--this   }
      { will be wSamplesPerBlock until we hit the last chunk of PCM     }
      { data that will not fill a complete block. so on the last block  }
      { we only encode that amount of data remaining...                 }

      dw := (dwSrcLen - dwInputPos) div cbSample;
      wBlockSize := Min(wSamplesPerBlock, dw);

      if (wBlockSize <= 0) then
         break;

      { copy the samples that we will be encoding into our small data }
      { samples buffer (this is faster than doing huge pointer arith  }
      { all of the time)                                              }

      GlobalMoveMem(PChar(@pSrc[dwInputPos])^,lpSamplesBuf^, wBlockSize * cbSample);

      { find the optimal predictor for each channel: to do this, we  }
      { must step through and encode using each coefficient set (one }
      { at a time) and determine which one has the least error from  }
      { the original data. the one with the least error is then used }
      { for the final encode (the 8th pass done below).              }
      {                                                              }
      { NOTE: keeping the encoded data of the one that has the least }
      { error at all times is an obvious optimization that should be }
      { done. in this way, we only need to do 7 passes instead of 8. }

      for i := 0 to MSADPCM_NUM_COEF-1 do
      begin
         { reset pointer to beginning of our temporary small data }
         { samples buffer                                         }
         lpSamples := lpSamplesBuf;

         { copy the coefficient pair for the current coefficient set }
         { we are using into more convenient/cheaper variables       }

         iCoef1 := lpwfADPCM^.aCoef[i].iCoef1;
         iCoef2 := lpwfADPCM^.aCoef[i].iCoef2;

         { we need to choose the first iDelta--to do this, we need    }
         { to look at the first few samples. for convenience, we copy }
         { the first ENCODE_DELTA_LOOKAHEAD samples (converted to     }
         { 16 bit samples) into a temporary buffer                    }

         for n := 0 to ENCODE_DELTA_LOOKAHEAD-1 do
         begin
            for m := 0 to bChannels-1 do
            begin
               if (bBitsPerSample <> 8) then
               begin
                  iSample := PSmallint(lpSamples)^;
                  inc(lpSamples,2);
               end
               else
               begin
                  iSample := Smallint(PByte(lpSamples)^ - 128) shl 8;
                  inc(lpSamples);
               end;
               aiSamples[n][m] := iSample;
            end;
         end;

         { now choose the first iDelta and setup the first two samples   }
         { based on the 16 samples we copied from the source data above  }
         { for each channel                                              }
         for m := 0 to bChannels-1 do
         begin
            { reset total error calculation for new block }
            adwTotalError[i][m] := 0;

            { first 2 samples will come from real data--compute }
            { starting from there                               }

            aiSamp1[m] := aiSamples[1][m];
            aiSamp2[m] := aiSamples[0][m];

            { calculate initial iDelta }
            iDelta := adpcmEncode4Bit_FirstDelta(iCoef1, iCoef2,
                                                 aiSamples[0][m],
                                                 aiSamples[1][m],
                                                 aiSamples[2][m],
                                                 aiSamples[3][m],
                                                 aiSamples[4][m]);
            aiDelta[m] := iDelta;
            aiFirstDelta[i][m] := iDelta;
         end;

         { step over first two complete samples--we took care of them above }
         lpSamples := @lpSamplesBuf[cbSample*2];

         { now encode the rest of the PCM data in this block--note    }
         { we start 2 samples ahead because the first two samples are }
         { simply copied into the ADPCM block header...               }

         for n := 2 to wBlockSize-1 do
         begin
            { each channel gets encoded independently... obviously. }
            for m := 0 to bChannels-1 do
            begin
               { yes, copy into cheaper variables because we access them a lot }
               iSamp1 := aiSamp1[m];
               iSamp2 := aiSamp2[m];
               iDelta := aiDelta[m];

               { calculate the prediction based on the previous two samples }
               lPrediction := sar((Longint(iSamp1) * iCoef1 +
                                   Longint(iSamp2) * iCoef2),MSADPCM_CSCALE);

               { grab the sample (for the current channel) to encode }
               { from the source and convert it to a 16 bit data if  }
               { necessary                                           }

               if (bBitsPerSample <> 8) then
               begin
                  iSample := PSmallint(lpSamples)^;
                  inc(lpSamples,2);
               end
               else
               begin
                  iSample := Smallint(PByte(lpSamples)^ - 128) shl 8;
                  inc(lpSamples);
               end;

               { encode it }
               lError := iSample - lPrediction;
               iOutput := (lError div iDelta);
               if (iOutput > MSADPCM_OUTPUT4_MAX) then
                   iOutput := MSADPCM_OUTPUT4_MAX
               else if (iOutput < MSADPCM_OUTPUT4_MIN) then
                        iOutput := MSADPCM_OUTPUT4_MIN;

               lSamp := lPrediction + (Longint(iDelta) * iOutput);

               if (lSamp > 32767) then
                   lSamp := 32767
               else if (lSamp < -32768) then
                        lSamp := -32768;

               { compute the next iDelta }
               iDelta := sar((gaiP4[iOutput and 15] * Longint(iDelta)),MSADPCM_PSCALE);
               if (iDelta < MSADPCM_DELTA4_MIN) then
                   iDelta := MSADPCM_DELTA4_MIN;

               { save updated values for this channel back into the }
               { original arrays...                                 }

               aiDelta[m] := iDelta;
               aiSamp2[m] := iSamp1;
               aiSamp1[m] := lSamp;

               { keep a running status on the error for the current }
               { coefficient pair for this channel                  }

               lError := lSamp - iSample;
               inc(adwTotalError[i][m],sar(lError * lError,7));
            end;
         end;
      end;

      { WHEW! we have now made 7 passes over the data and calculated   }
      { the error for each--so it's time to find the one that produced }
      { the lowest error and use that predictor (this is for each      }
      { channel of course)                                             }
      for m := 0 to bChannels-1 do
      begin
         abBestPredictor[m] := 0;
         dw := adwTotalError[0][m];
         for i := 1 to MSADPCM_NUM_COEF-1 do
         begin
            if (adwTotalError[i][m] < dw) then
            begin
               abBestPredictor[m] := i;
               dw := adwTotalError[i][m];
            end;
         end;
      end;

      { reset pointer to beginning of our temporary samples buffer--     }
      { we're going to make our final pass on the data with the optimal  }
      { predictor that we found above                                    }

      lpSamples := lpSamplesBuf;

      { grab first iDelta from our precomputed first deltas that we  }
      { calculated above                                             }

      for m := 0 to bChannels-1 do
      begin
         i := abBestPredictor[m];
         aiDelta[m] := aiFirstDelta[i][m];
      end;

      { get the first two samples from the source data (so we can write  }
      { them into the ADPCM block header and use them in our prediction  }
      { calculation when encoding the rest of the data).                 }

      if (bBitsPerSample <> 8) then
      begin
         for m := 0 to bChannels-1 do
         begin
            aiSamp2[m] := PSmallint(lpSamples)^;
            inc(lpSamples,2);
         end;
         for m := 0 to bChannels-1 do
         begin
            aiSamp1[m] := PSmallint(lpSamples)^;
            inc(lpSamples,2);
         end;
      end
      else
      begin
         for m := 0 to bChannels-1 do
         begin
            aiSamp2[m] := (Smallint(PByte(lpSamples)^) - 128) shl 8;
            inc(lpSamples);
         end;
         for m := 0 to bChannels-1 do
         begin
            aiSamp1[m] := (Smallint(PByte(lpSamples)^) - 128) shl 8;
         end;
      end;

      { write the block header for the encoded data                     }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -