MMStretch.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:19k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit MMStretch;
  2. (*-------------------------------------------------------------------
  3.  * Time domain harmonic scaling by
  4.  * Pointer Inteval Controled OverLap and ADD (PICOLA) Method
  5.  * C version by IKEDA Mikio
  6.  * original argolithm is developed by MORITA Naotaka
  7.  * about detail, see original paper.
  8.  *-------------------------------------------------------------------
  9.  * Usage
  10.  *  PICOLA <source signal> <companded (destination) signal>
  11.  *    <compansion ratio>
  12.  *         <window length> <pitch minimum> <pitch maximum>
  13.  * Last three arguments can be abbriviated.
  14.  *------------------------------------------------------------------*)
  15.  // Does not work (horrible quality) leave it for now....
  16. interface
  17. uses
  18.     SysUtils,
  19.     Windows,
  20.     Classes,
  21.     MMSystem,
  22.     MMRegs,
  23.     MMObj,
  24.     MMDSPObj,
  25.     MMPCMSup,
  26.     MMUtils;
  27. type
  28.    EMMTimeStretchError = class(Exception);
  29.    {-- TMMTimeStretch ---------------------------------------------------------}
  30.    TMMTimeStretch = class(TMMDSPComponent)
  31.    private
  32.       FEnabled       : Boolean;
  33.       FOpen          : Boolean;
  34.       FFirstRead     : Boolean;
  35. //      FPitch         : Float;
  36.       FWaveHdr       : TMMWaveHdr;
  37.       FRealBufSize   : Longint;
  38.       FBytesRead     : Longint;
  39.       FMoreBuffers   : Boolean;
  40.       FWriteBuffer   : PChar;
  41.       FBytesWritten  : Longint;
  42.       FDone          : Boolean;
  43.       procedure SetEnabled(aValue: Boolean);
  44.   //    procedure SetPitch(aValue: Float);
  45.       function  ReadData(Buffer: PChar; dwLength: Longint; var MoreData: Boolean): Longint;
  46.       function  WriteData(Buffer: PChar; dwLength: Longint): Longint;
  47.       procedure ReadFromInput(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  48.    protected
  49.       procedure SetPWaveFormat(aValue: PWaveFormatEx); override;
  50.       procedure Opened; override;
  51.       procedure Closed; override;
  52.       procedure Started; override;
  53.       procedure Reseting; override;
  54.       procedure BufferReady(lpwh: PWaveHdr); override;
  55.       procedure BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean); override;
  56.    public
  57.       constructor Create(aOwner: TComponent); override;
  58.       destructor Destroy; override;
  59.       procedure Open;
  60.       procedure Close;
  61.       procedure Reset;
  62.    published
  63.       property Input;
  64.       property Output;
  65.       property Enabled: Boolean read FEnabled write SetEnabled default True;
  66.     //  property Pitch: Float read FPitch write SetPitch;
  67.    end;
  68. procedure StretchFile(SrcFile,DstFile: String);
  69. implementation
  70. {---- find maximum covariance  = pitch ----------------------------------------}
  71. function covpitch(pitmin, pitmax, length: integer; _is: array of Smallint): integeR;
  72. var
  73.   i,j,pitch: integer;
  74.   covst, covs0t, covmax, s: Float;
  75. begin
  76.    covmax := 0.0;
  77.    pitch := pitmin;
  78.    for i := pitmin to pitmax do
  79.    begin
  80.       covst := 0.0;
  81.       covs0t := 0.0;
  82.       for j := 0 to length-1 do
  83.       begin
  84.  s := _is[i+j];
  85.  covs0t := covs0t + s * s;
  86.  covst  := covst + _is[j] * s;
  87.       end;
  88.       covst := covst / sqrt(covs0t);
  89.       if (covst >= covmax) then
  90.       begin
  91.          covmax := covst;
  92.          pitch := i;
  93.       end;
  94.    end;
  95.    Result := pitch;
  96. end;
  97. {------------ PICOLA OverLap and Add (picOLA) stage ---------------------------}
  98. procedure ola(pitch: integer; is1, is2: PSmallint);
  99. var
  100.    i: integer;
  101.    s, w: Float;
  102. begin
  103.    for i := 0 to pitch-1 do
  104.    begin
  105.       w := i / (pitch - 1);
  106.       s :=  is1^ * (1.0 - w) + is2^ * w;
  107.       inc(is1);
  108.       is2^ := Trunc(s);
  109.       inc(is2);
  110.    end;
  111. end;
  112. {------------------------------------------------------------------------------}
  113. function amdfpitch(pitmin, pitmax, length: integer; _is: array of Smallint): integer;
  114. var
  115.    i, j, diff, acc, accmin, pitch: integer;
  116. begin
  117.    pitch := pitmin;
  118.    accmin := 0;
  119.    for j := 0 to length-1 do
  120.    begin
  121.       diff := _is[j+pitmin] - _is[j];
  122.       if (diff > 0) then
  123.           accmin := accmin + diff
  124.       else
  125.           accmin := accmin - diff;
  126.    end;
  127.    for i := pitmin+1 to pitmax do
  128.    begin
  129.       acc := 0;
  130.       for j := 0 to length-1 do
  131.       begin
  132.          diff := _is[i+j] - _is[j];
  133.  if (diff > 0) then
  134.              acc := acc + diff
  135.          else
  136.      acc := acc - diff;
  137.       end;
  138.       if (acc < accmin) then
  139.       begin
  140.  accmin := acc;
  141.  pitch := i;
  142.       end;
  143.    end;
  144.    Result := pitch;
  145. end;
  146. var
  147.    _is : array[0..4096] of Smallint; // signal buffer
  148.    rate: Float = 1.1; // compansion rate
  149. //case of less than 1.0 compression,
  150. //case of greater than 1.0 expansion
  151.    rcomp: Float; // internal compansion ratio
  152.    sl: Float;
  153.    err: float = 0.0; // compansion rate error estimate
  154.    acclen: Float = 0.0;
  155.    pitmin: integer = 32;  // minimal pitch period //
  156.    pitmax: integer = 1024; // maximal pitch period //
  157.    pitch : integer;    // detected pitch period */
  158.    length: integer = 1024;
  159.    total: integer;
  160.    nread: integer; // number of read samples (from file) */
  161.    wantread: integer; // desired number of read samples */
  162.    lcp: integer; // number of copy samples */
  163.    point: integer; // PICOLA's pointer */
  164. //   i: integer; // loop counter */
  165.    lproc: integer = 0; // processed speech samples */
  166.    Src,Dst: THandle;
  167. procedure StretchFile(SrcFile,DstFile: String);
  168. var
  169.    i: integer;
  170. begin
  171.    // length := atoi(argv[4]); option
  172.    // pitmin := atoi(argv[5]); option
  173.    // pitmax := atoi(argv[6]); option
  174.    //-------------- error check and initialize ---------------------
  175.    {
  176.     if (rate <= 0.0 || rate == 1.0)
  177.     begin
  178.        printf("illeagal compansion rate !!n");
  179. exit(0);
  180.     end;
  181.     if (pitmin < 16)
  182.     begin
  183.         printf("pitch detection minimum threshold modified !!n");
  184. pitmin = 16;
  185.     end;
  186.     if (pitmax > 256)
  187.     begin
  188.         printf("pitch detection maximum threshold modified !!n");
  189. pitmax = 256;
  190.     end;
  191.     if (length <= 64 || length + pitmax >= 1024)
  192.     begin
  193. printf("frame length out of range !!n");
  194. exit(0);
  195.     end;
  196. }
  197.     total := length + pitmax;
  198.     if (rate >= 1.0) then
  199.     begin
  200.        // TODO:rate darf nicht 1.0 sein, also bei rate := 1.0 skippen
  201.        rcomp := 1.0  / (rate - 1.0);
  202.     end
  203.     else if (rate > 0) then
  204.     begin
  205.        rcomp := rate / (1.0 - rate);
  206.     end
  207.     else
  208.     begin
  209.        // fprintf(stderr, "Error from %s: illeagal compansion rate!n", argv[0]);
  210.        // exit(0);
  211.     end;
  212.     Src := FileOpen(SrcFile,fmOpenRead);
  213.     Dst := FileCreate(DstFile);
  214.     //------------------- body ---------------
  215.     wantread := total;  // total muss gesetzt werden !!!
  216.     nread := FileRead(Src,_is, 2*wantread) div 2;
  217.     while (nread = wantread) do
  218.     begin
  219.        //---- pitch extraction ----
  220.        pitch := amdfpitch(pitmin, pitmax, length, _is);
  221.        //---- PICOLA OverLap and ADD stage ----//
  222.        if (rate < 1.0) then
  223.        begin
  224.            ola(pitch, @_is, @_is[pitch]);
  225.            point := pitch;
  226.        end
  227.        else
  228.        begin
  229.           FileWrite(Dst,_is, 2*pitch);
  230.           ola(pitch, @_is[pitch], @_is);
  231.   point := 0;
  232.        end;
  233.        //---- compensate compansion rate ----*/
  234.        sl := pitch * rcomp;
  235.        lcp := trunc(sl);
  236.        err := err + lcp - sl;
  237.        if (err >= 0.5) then
  238.        begin
  239.           dec(lcp);
  240.           err := err - 1.0;
  241.        end
  242.        else if (err <= -0.5) then
  243.        begin
  244.           inc(lcp);
  245.           err := err + 1.0;
  246.        end;
  247.        lproc := lproc + pitch;
  248.        //---- PICOLA Pointer Interval Control (PIC) stage ----*/
  249. wantread := point + lcp;
  250. if (wantread > total) then
  251.         begin
  252.            wantread := total - point;
  253.    FileWrite(Dst,_is[point], 2*wantread);
  254.    lcp := lcp - wantread;
  255.    wantread := total;
  256.    while (lcp > 0) do
  257.            begin
  258.               if (lcp <= total) then
  259.               begin
  260.                  wantread := lcp;
  261.          nread := FileRead(Src,_is, 2*wantread)div 2;
  262.          FileWrite(Dst,_is, 2*nread);
  263.          if (nread <> wantread) then
  264.                      break;
  265.       wantread := total;
  266.       nread := FileRead(Src,_is, 2*wantread)div 2;
  267.               end
  268.               else
  269.               begin
  270.                  nread := FileRead(Src,_is, 2*wantread)div 2;
  271.          FileWrite(Dst,_is, 2*nread);
  272.          if (nread <> wantread) then
  273.          break;
  274.               end;
  275.               lcp := lcp - total;
  276.            end;
  277.         end
  278.         else
  279.         begin
  280.            FileWrite(Dst,_is[point], 2*lcp);
  281.    point := total - wantread;
  282.    // shift to next pitch period
  283.            for i := 0 to point-1 do
  284.            begin
  285.               _is[i] := _is[i+wantread];
  286.            end;
  287.            nread := FileRead(Src,_is[point], 2*wantread)div 2;
  288.         end;
  289.     end;
  290.     // write rest */
  291.     FileWrite(Dst,_is, 2*(total - wantread + nread));
  292.     FileClose(Src);
  293.     FileClose(Dst);
  294. end;
  295. {== TMMTimeStretch ============================================================}
  296. constructor TMMTimeStretch.Create(aOwner: TComponent);
  297. begin
  298.    inherited Create(aOwner);
  299.    FEnabled     := True;
  300.    FOpen        := False;
  301.    FWriteBuffer := nil;
  302.    FFirstRead   := True;
  303.    //SetPitch(0.0);
  304. end;
  305. {-- TMMTimeStretch ------------------------------------------------------------}
  306. destructor TMMTimeStretch.Destroy;
  307. begin
  308.    Close;
  309.    inherited Destroy;
  310. end;
  311. {-- TMMTimeStretch ------------------------------------------------------------}
  312. procedure TMMTimeStretch.SetEnabled(aValue: Boolean);
  313. begin
  314.    if (aValue <> FEnabled) then
  315.    begin
  316.       FEnabled := aValue;
  317.       if FEnabled then Reset;
  318.    end;
  319. end;
  320. (*
  321. {-- TMMTimeStretch ------------------------------------------------------------}
  322. procedure TMMTimeStretch.SetPitch(aValue: Float);
  323. begin
  324. //   FPitch := MinMaxR(aValue,-50.0,+50.0);
  325. //   FPitchInc := Trunc((FPitch+50)*65536/100+32768);
  326. end;
  327. *)
  328. {-- TMMTimeStretch ------------------------------------------------------------}
  329. procedure TMMTimeStretch.SetPWaveFormat(aValue: PWaveFormatEx);
  330. begin
  331.    if (aValue <> nil) then
  332.    begin
  333.       if not (csDesigning in ComponentState) then
  334.          if not pcmIsValidFormat(aValue) or (aValue^.wBitsPerSample = 8) then
  335.             raise EMMTimeStretchError.Create(LoadResStr(IDS_INVALIDFORMAT));
  336.    end;
  337.    inherited SetPWaveFormat(aValue);
  338. end;
  339. {-- TMMTimeStretch ------------------------------------------------------------}
  340. procedure TMMTimeStretch.Open;
  341. begin
  342.    if not FOpen then
  343.    begin
  344.       FRealBufSize               := Max(BufferSize,Max(QUEUE_READ_SIZE,BufferSize));
  345.       FWaveHdr.wh.dwBufferLength := 2*FRealBufSize;
  346.       FWaveHdr.wh.lpData         := GlobalAllocMem(FWaveHdr.wh.dwBufferLength);
  347.       FWriteBuffer               := GlobalAllocMem(FRealBufSize);
  348.       FFirstRead                 := True;
  349.       FOpen                      := True;
  350.    end;
  351. end;
  352. {-- TMMTimeStretch ------------------------------------------------------------}
  353. procedure TMMTimeStretch.Close;
  354. begin
  355.    if FOpen then
  356.    begin
  357.       FOpen := False;
  358.       GlobalFreeMem(Pointer(FWaveHdr.wh.lpData));
  359.       GlobalFreeMem(Pointer(FWriteBuffer));
  360.    end;
  361. end;
  362. {-- TMMTimeStretch ------------------------------------------------------------}
  363. procedure TMMTimeStretch.Reset;
  364. begin
  365.    if FOpen then
  366.    begin
  367.       FWaveHdr.wh.dwBytesRecorded := 0;
  368.       FWaveHdr.LoopRec.dwLooping  := False;
  369.       FBytesRead    := 0;
  370.       FBytesWritten := 0;
  371.       FFirstRead    := True;
  372.       FDone         := False;
  373.    end;
  374. end;
  375. {-- TMMTimeStretch ------------------------------------------------------------}
  376. procedure TMMTimeStretch.Opened;
  377. begin
  378.    Open;
  379.    inherited Opened;
  380. end;
  381. {-- TMMTimeStretch ------------------------------------------------------------}
  382. procedure TMMTimeStretch.Closed;
  383. begin
  384.    Close;
  385.    inherited Closed;
  386. end;
  387. {-- TMMTimeStretch ------------------------------------------------------------}
  388. procedure TMMTimeStretch.Reseting;
  389. begin
  390.    Reset;
  391.    inherited Reseting;
  392. end;
  393. {-- TMMTimeStretch ------------------------------------------------------------}
  394. procedure TMMTimeStretch.Started;
  395. begin
  396.    Reset;
  397.    inherited Started;
  398. end;
  399. {-- TMMTimeStretch ------------------------------------------------------------}
  400. function TMMTimeStretch.ReadData(Buffer: PChar; dwLength: Longint; var MoreData: Boolean): Longint;
  401. Label _Again;
  402. var
  403.    nRead,nBytes: Longint;
  404. begin
  405.    nRead := 0;
  406.    MoreData := False;
  407.    with FWaveHdr.wh do
  408.    begin
  409. _Again:
  410.       nBytes := dwBytesRecorded - FBytesRead;
  411.       if (nBytes > 0) then
  412.       begin
  413.          nBytes := Min(nBytes,dwLength);
  414.          GlobalMoveMem((FWaveHdr.wh.lpData+FBytesRead)^,(Buffer+nRead)^,nBytes);
  415.          inc(nRead,nBytes);
  416.          inc(FBytesRead,nBytes);
  417.          dec(dwLength,nBytes);
  418.       end;
  419.       { do we need more data ? }
  420.       if (dwLength > 0) and not FDone then
  421.       begin
  422.          dwBytesRecorded := 0;
  423.          (*
  424.          // TODO: LoopHandling !!!!
  425.          if FWaveHdr.LoopRec.dwLooping then
  426.          begin
  427.             PMMWaveHdr(lpwh)^.LoopRec.dwLooping := True;
  428.             PMMWaveHdr(lpwh)^.LoopRec.dwLoopTmpCnt := FWaveHdr.LoopRec.dwLoopTmpCnt;
  429.             FWaveHdr.LoopRec.dwLooping := False;
  430.          end;
  431.          FWaveHdr.LoopRec.dwLoop := PMMWaveHdr(lpwh)^.LoopRec.dwLoop;
  432.          if FWaveHdr.LoopRec.dwLoop then
  433.          begin
  434.             FWaveHdr.LoopRec.dwLoopCnt    := PMMWaveHdr(lpwh)^.LoopRec.dwLoopCnt;
  435.             FWaveHdr.LoopRec.dwLoopTmpCnt := PMMWaveHdr(lpwh)^.LoopRec.dwLoopTmpCnt;
  436.             FWaveHdr.LoopRec.dwLooping    := False;
  437.          end;
  438.          *)
  439.          FMoreBuffers := False;
  440.          inherited BufferLoad(@FWaveHdr,FMoreBuffers);
  441.          if not FMoreBuffers or (dwBytesRecorded <= 0) then FDone := True;
  442.          FBytesRead := 0;
  443.          if (dwBytesRecorded > 0) then goto _Again;
  444.       end;
  445.       MoreData := FMoreBuffers or (dwBytesRecorded-FBytesRead > 0);
  446.    end;
  447.    Result := nRead;
  448. end;
  449. {-- TMMTimeStretch ------------------------------------------------------------}
  450. function TMMTimeStretch.WriteData(Buffer: PChar; dwLength: Longint): Longint;
  451. begin
  452.    GlobalMoveMem(Buffer^,(FWriteBuffer+FBytesWritten)^,dwLength);
  453.    inc(FBytesWritten,dwlength);
  454.    Result := FBytesWritten;
  455. end;
  456. {-- TMMTimeStretch ------------------------------------------------------------}
  457. procedure TMMTimeStretch.ReadFromInput(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  458. var
  459.    i: integer;
  460.    nBytes: Longint;
  461.    HasMoreData: Boolean;
  462. begin
  463.    if (Input <> nil) then
  464.    begin
  465.       // TODO: wenn geskippt wird weil keine pitch 膎derung dann aufpassen das MoreBuffers richtig gesetzt wird
  466.       HasMoreData := True;
  467.    //   lpwh.dwBytesRecorded := ReadData(lpwh^.lpData,lpwh.dwBufferLength,MoreBuffers);
  468.       total := length + pitmax;
  469.       if (rate >= 1.0) then
  470.       begin
  471.          // TODO:rate darf nicht 1.0 sein, also bei rate := 1.0 skippen
  472.          rcomp := 1.0  / (rate - 1.0);
  473.       end
  474.       else if (rate > 0) then
  475.       begin
  476.          rcomp := rate / (1.0 - rate);
  477.       end
  478.       else
  479.       begin
  480.          // fprintf(stderr, "Error from %s: illeagal compansion rate!n", argv[0]);
  481.          // exit(0);
  482.       end;
  483.       //------------------- body ---------------
  484.       // Todo: nur bei Initial read
  485.       if FFirstRead then
  486.       begin
  487.          wantread := total;
  488.          nread := ReadData(@_is, 2*wantread, HasMoreData) div 2;
  489.          FFirstRead := False;
  490.       end;
  491.       while (nread = wantread) and (FBytesWritten < lpwh.dwBufferLength) do
  492.       begin
  493.          //---- pitch extraction ----
  494.          pitch := amdfpitch(pitmin, pitmax, length, _is);
  495.          //---- PICOLA OverLap and ADD stage ----//
  496.          if (rate < 1.0) then
  497.          begin
  498.             ola(pitch, @_is, @_is[pitch]);
  499.             point := pitch;
  500.          end
  501.          else
  502.          begin
  503.             WriteData(@_is, 2*pitch);
  504.             ola(pitch, @_is[pitch], @_is);
  505.     point := 0;
  506.          end;
  507.          //---- compensate compansion rate ----*/
  508.          sl := pitch * rcomp;
  509.          lcp := trunc(sl);
  510.          err := err + lcp - sl;
  511.          if (err >= 0.5) then
  512.          begin
  513.             dec(lcp);
  514.             err := err - 1.0;
  515.          end
  516.          else if (err <= -0.5) then
  517.          begin
  518.             inc(lcp);
  519.             err := err + 1.0;
  520.          end;
  521.          lproc := lproc + pitch;
  522.          //---- PICOLA Pointer Interval Control (PIC) stage ----*/
  523.  wantread := point + lcp;
  524.  if (wantread > total) then
  525.          begin
  526.             wantread := total - point;
  527.     WriteData(@_is[point], 2*wantread);
  528.     lcp := lcp - wantread;
  529.     wantread := total;
  530.     while (lcp > 0) do
  531.             begin
  532.                if (lcp <= total) then
  533.                begin
  534.                   wantread := lcp;
  535.           nread := ReadData(@_is, 2*wantread,HasMoreData)div 2;
  536.           WriteData(@_is, 2*nread);
  537.           if (nread <> wantread) then
  538.                       break;
  539.        wantread := total;
  540.        nread := ReadData(@_is, 2*wantread,HasMoreData)div 2;
  541.                end
  542.                else
  543.                begin
  544.                   nread := ReadData(@_is, 2*wantread,HasMoreData)div 2;
  545.           WriteData(@_is, 2*nread);
  546.           if (nread <> wantread) then
  547.               break;
  548.                end;
  549.                lcp := lcp - total;
  550.             end;
  551.          end
  552.          else
  553.          begin
  554.             WriteData(@_is[point], 2*lcp);
  555.     point := total - wantread;
  556.     // shift to next pitch period
  557.     for i := 0 to point-1 do
  558.             begin
  559.                _is[i] := _is[i+wantread];
  560.             end;
  561.             nread := ReadData(@_is[point], 2*wantread,HasMoreData)div 2;
  562.          end;
  563.       end;
  564.       if not HasMoreData then
  565.       begin
  566.          // write rest */
  567.          WriteData(@_is, 2*(total - wantread + nread));
  568.       end;
  569.       nBytes := Min(FBytesWritten,lpwh.dwBufferLength);
  570.       GlobalMoveMem(FWriteBuffer^,lpwh^.lpData^,nBytes);
  571.       GlobalMoveMem((FWriteBuffer+nBytes)^,FWriteBuffer^,FBytesWritten-nBytes);
  572.       dec(FBytesWritten,nBytes);
  573.       lpwh^.dwBytesRecorded := nBytes;
  574.       MoreBuffers := HasMoreData or (FBytesWritten > 0);
  575.    end
  576.    else lpwh^.dwBytesRecorded := 0;
  577. end;
  578. {-- TMMTimeStretch ------------------------------------------------------------}
  579. procedure TMMTimeStretch.BufferReady(lpwh: PWaveHdr);
  580. begin
  581.    if Enabled and FOpen then
  582.    begin
  583.       { TODO: Pitch f黵 recording schreiben }
  584.    end;
  585.    inherited BufferReady(lpwh);
  586. end;
  587. {-- TMMTimeStretch ------------------------------------------------------------}
  588. procedure TMMTimeStretch.BufferLoad(lpwh: PWaveHdr; var MoreBuffers: Boolean);
  589. begin
  590.    // TODO: wenn Enabled auf False gesetzt wird dann ev. noch im Puffer befindliche Daten abspielen.
  591.    if Enabled and FOpen {and ((FPitchInc <> $10000) or (FWaveHdr.wh.dwBytesRecorded - FBytesRead > 0))} then
  592.    begin
  593.       ReadFromInput(lpwh,MoreBuffers);
  594.    end
  595.    else inherited BufferLoad(lpwh, MoreBuffers);
  596. end;
  597. end.