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

📄 mmadpcm.pas

📁 一套及时通讯的原码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
      {                                                                 }
      { the block header is composed of the following data:             }
      {      1 byte predictor per channel                               }
      {      2 byte delta per channel                                   }
      {      2 byte first sample per channel                            }
      {      2 byte second sample per channel                           }
      {                                                                 }
      {  this gives us (7 * bChannels) bytes of header information      }
      {  so first write the 1 byte predictor for each channel into the  }
      {  destination buffer                                             }
      for m := 0 to bChannels-1 do
      begin
         PByte(pDst)^ := abBestPredictor[m];
         inc(pDst);
      end;

      { now write the 2 byte delta per channel...  }
      for m := 0 to bChannels-1 do
      begin
         PSmallint(pDst)^ := aiDelta[m];
         inc(pDst,2);
      end;

      { finally, write the first two samples (2 bytes each per channel) }
      for m := 0 to bChannels-1 do
      begin
         PSmallint(pDst)^ := aiSamp1[m];
         inc(pDst,2);
      end;
      for m := 0 to bChannels-1 do
      begin
         PSmallint(pDst)^ := aiSamp2[m];
         inc(pDst,2);
      end;

      { the number of bytes that we have written to the destination   }
      { buffer is (7 * bChannels)--so add this to our total number of }
      { bytes written to the destination.. for our return value.      }

      inc(dwTotalConverted,wBlockHeaderBytes);

      { we have written the header for this block--now write the data    }
      { chunk (which consists of a bunch of encoded nibbles). note that  }
      { we start our count at 2 because we already wrote the first       }
      { two samples into the destination buffer as part of the header    }

      wFirstNibble := 1;
      for n := 2 to wBlockSize-1 do
      begin
         { each channel gets encoded independently... obviously. }
         for m := 0 to bChannels-1 do
         begin
            { use our chosen best predictor and grab the coefficient }
            { pair to use for this channel...                        }

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

            { 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 to encode--convert it to 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;
            end;

            { encode the sample }
            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;

            { we have another nibble of encoded data--either combine   }
            { this with the previous nibble and write out a full       }
            { byte, or save this nibble for the next nibble to be      }
            { combined into a full byte and written to the destination }
            { buffer... uhg!                                           }
            if (wFirstNibble <> 0) then
            begin
               wNextWrite := sal(iOutput and 15,4);
               wFirstNibble := 0;
            end
            else
            begin
               PByte(pDst)^ := (wNextWrite or (iOutput and 15));
               inc(pDst);
               inc(dwTotalConverted);
               inc(wFirstNibble);
            end;
         end;
      end;
      inc(dwInputPos,wBlockSize * cbSample);
   end;

   { free the memory used for our small data buffer and return the number }
   { of bytes that we wrote into the destination buffer...                }

   GlobalFreePtr(lpSamplesBuf);

   Result := dwTotalConverted;
end;

(*============================================================================*)
(*                                                                            *)
(*  the code below provides 'support' routines for building/verifying ADPCM   *)
(*  headers, etc.                                                             *)
(*                                                                            *)
(*  the coefficient pairs that should be in the wave format header for        *)
(*  the Microsoft 4 Bit ADPCM algorithm. the code to copy the coefficients    *)
(*  into the wave format header is shown:                                     *)
(*                                                                            *)
(*      short gaiCoef1[] = { 256,  512,  0, 192, 240,  460,  392 };           *)
(*      short gaiCoef2[] = {   0, -256,  0,  64,   0, -208, -232 };           *)
(*                                                                            *)
(*      for (w = 0; w < MSADPCM_NUM_COEF; w++)                                *)
(*      {                                                                     *)
(*          lpwfADPCM->aCoef[w].iCoef1 = gaiCoef1[w];                         *)
(*          lpwfADPCM->aCoef[w].iCoef2 = gaiCoef2[w];                         *)
(*      }                                                                     *)
(*                                                                            *)
(*============================================================================*)
const
     gaiCoef1: array[0..6]of Smallint = (256,  512,  0, 192, 240,  460,  392);
     gaiCoef2: array[0..6]of Smallint = (0, -256,  0,  64,   0, -208, -232);

function adpcmIsValidFormat(lpwfx: PWaveFormatEx): Boolean;
var
   lpwfADPCM: PADPCMWaveFormat;
   w: WORD;

begin
   if (lpwfx = nil) or (lpwfx^.wFormatTag <> WAVE_FORMAT_ADPCM) or
      (lpwfx^.wBitsPerSample <> 4) or (lpwfx^.nChannels < 1) or
      (lpwfx^.nChannels > MSADPCM_MAX_CHANNELS) then
   begin
      Result := False;
      exit;
   end;

   { check coef's to see if it is Microsoft's standard 4 Bit ADPCM }
   lpwfADPCM := Pointer(lpwfx);
   if (lpwfADPCM^.wNumCoef <> MSADPCM_NUM_COEF) then
   begin
      Result := False;
      exit;
   end;

   for w := 0 to MSADPCM_NUM_COEF-1 do
   begin
      if (lpwfADPCM^.aCoef[w].iCoef1 <> gaiCoef1[w]) or
         (lpwfADPCM^.aCoef[w].iCoef2 <> gaiCoef2[w]) then
      begin
         Result := False;
         exit;
      end;
   end;
   Result := True;
end;

{==============================================================================}
function adpcmBuildFormatHeader(lpwfxSrc, lpwfxDst: PWaveFormatEx; PCMBitLength,DestChannels,DestRate: integer): Boolean;
var
   lpwfADPCM: PADPCMWaveFormat;
   wBlockAlign,
   wChannels,
   wSamplesPerSec,
   wBitsPerSample,
   wHeaderBytes,
   w: Word;
   dw: DWORD;

begin
   { if the source format is PCM, then build an ADPCM destination format }
   { header... assuming the PCM format header is valid.                  }

   if (lpwfxSrc^.wFormatTag = WAVE_FORMAT_PCM) then
   begin
      if not pcmIsValidFormat(lpwfxSrc) then
      begin
         Result := False;
         exit;
      end;

      lpwfADPCM := Pointer(lpwfxDst);

      if (DestChannels > 0) then
          wChannels := DestChannels
      else
          wChannels := lpwfxSrc^.nChannels;

      if (DestRate > 0) then
          wSamplesPerSec := DestRate
      else
          wSamplesPerSec := lpwfxSrc^.nSamplesPerSec;

      wBitsPerSample := 4;

      { fill in destination header with appropriate ADPCM stuff based }
      { on source PCM header...                                       }

      lpwfxDst^.wFormatTag     := WAVE_FORMAT_ADPCM;

      lpwfxDst^.nSamplesPerSec := wSamplesPerSec;
      lpwfxDst^.nChannels      := wChannels;
      lpwfxDst^.wBitsPerSample := wBitsPerSample;

      { choose a block alignment that makes sense for the sample rate  }
      { that the original PCM data is. basically, this needs to be     }
      { some reasonable number to allow efficient streaming, etc.      }
      {                                                                }
      { don't let block alignment get too small...                     }


      wBlockAlign := 256 * wChannels;
      if (wSamplesPerSec > 11025) then
          wBlockAlign := wBlockAlign * (wSamplesPerSec div 11000);

      lpwfxDst^.nBlockAlign := wBlockAlign;

      { compute that 'samples per block' that will be in the encoded   }
      { ADPCM data blocks. this is determined by subtracting out the   }
      { 'other info' contained in each block--a block is composed of   }
      {  a header followed by the encoded data.                        }
      {                                                                }
      { the block header is composed of the following data:            }
      {     1 byte predictor per channel                               }
      {     2 byte delta per channel                                   }
      {     2 byte first sample per channel                            }
      {     2 byte second sample per channel                           }
      {                                                                }
      { this gives us (7 * wChannels) bytes of header information that }
      { contains our first two full samples (so we add two below).     }

      wHeaderBytes := (7 * wChannels);

      w := (wBlockAlign - wHeaderBytes) * 8;
      lpwfADPCM^.wSamplesPerBlock := (w div (wBitsPerSample * wChannels)) + 2;

      { now compute the avg bytes per second (man this code bites!) }
      dw := ((Longint(wBitsPerSample) * wChannels *
                      Longint(lpwfxDst^.nSamplesPerSec)) div 8);

      lpwfxDst^.nAvgBytesPerSec := (dw + wHeaderBytes + ((dw div wBlockAlign) * wHeaderBytes));

      { fill in the cbSize field of the extended wave format header.    }
      { this number is the number of _EXTRA BYTES_ *after* the end      }
      { of the WAVEFORMATEX structure that are need for the compression }
      { format.                                                         }
      {                                                                 }
      { for Microsoft's 4 Bit ADPCM format, this number is 32:          }

      lpwfxDst^.cbSize := sizeof(TADPCMWAVEFORMAT) - sizeof(TWaveFormatEx) +
                                 ((MSADPCM_NUM_COEF-1) * sizeof(TADPCMCOEFSET));

      { copy the Microsoft 4 Bit ADPCM coef's into the header }
      lpwfADPCM^.wNumCoef := MSADPCM_NUM_COEF;

      for w := 0 to MSADPCM_NUM_COEF-1 do
      begin
         lpwfADPCM^.aCoef[w].iCoef1 := gaiCoef1[w];
         lpwfADPCM^.aCoef[w].iCoef2 := gaiCoef2[w];
      end;

      Result := True;
   end
   else if (lpwfxSrc^.wFormatTag = WAVE_FORMAT_ADPCM) then
   begin
      { if the source format is ADPCM, then build an appropriate PCM header }
      if not adpcmIsValidFormat(lpwfxSrc) then
      begin
         Result := False;
         exit;
      end;

      if (DestChannels > 0) then
          wChannels := DestChannels
      else
          wChannels := lpwfxSrc^.nChannels;

      if (DestRate > 0) then
          wSamplesPerSec := DestRate
      else
          wSamplesPerSec := lpwfxSrc^.nSamplesPerSec;

      if (PCMBitLength > 0) then
          wBitsPerSample := PCMBitLength
      else
          wBitsPerSample := 16;

      { fill in the info for our destination format... }
      pcmBuildWaveHeader(lpwfxDst,wBitsPerSample, wChannels, wSamplesPerSec);

      Result := True;
   end
   else Result := False;
end;

end.

⌨️ 快捷键说明

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