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

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49(0)351-8037944               =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/index.html               =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 23.11.98 - 13:42:36 $                                        =}
  24. {========================================================================}
  25. unit MMWaveIO;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     SysUtils,
  36.     MMSystem,
  37.     MMRegs,
  38.     MMRiff,
  39.     MMUtils,
  40.     MMAbout;
  41. const
  42.     { file open flags for waveio functions }
  43.     RIFF_FILE      = $0001;
  44.     RIFF_RESOURCE  = $0002;
  45.     RIFF_MEMORY    = $0004;
  46.     { get the extra Info only }
  47.     RIFF_INFO_ONLY = $0008;
  48.     { we have a RAW file }
  49.     RAW_FILE       = $0010;
  50. type
  51.     PWAVEIOCB = ^TWAVEIOCB;
  52.     TWAVEIOCB = packed record        { do not change the first items !!!! }
  53.       dwSize          : DWORD;       { size for the structure             }
  54.       dwFlags         : DWORD;       { flags used to open the file        }
  55.       hmmio           : THMMIO;      { handle to open file                }
  56.       ckRIFF,ckDATA   : TMMCKINFO;   { the current RIFF and data chunk    }
  57.       hMem            : THandle;     { <> 0 if we have a res. file, free it !}
  58.       dwFileSize      : DWORD;     { the filesize for the actual file   }
  59.       dwDataBytes     : DWORD;       { the data size for the actual file  }
  60.       dwDataOffset    : DWORD;       { offset from data chunk             }
  61.       dwDataSamples   : DWORD;       { how much samples in the file       }
  62.       dwFirstSample   : DWORD;       { the first sample to read           }
  63.       dwLastSample    : DWORD;       { the last Sample to read            }
  64.       dwBytesLeft     : DWORD;       { how many bytes to play             }
  65.       dwPosition      : DWORD;       { the current file position          }
  66.       lpFilePath      : PChar;       { filename from the actual file      }
  67.       lpDisp          : PDispList;   { pointer to display chunk's         }
  68.       lpInfo          : PInfoChunk;  { pointer to info chunk              }
  69.       fAvgBytesPerSec : Double;
  70.       { this MUST be the last element in this structure--its length is  }
  71.       { not fixed; use ab[] to get at any extra bytes (note! the length }
  72.       { of ab[] is in wfx.cbSize--this CAN be zero!)                    }
  73.       wfx             : TWaveFormatEx;
  74.       ab              : array[0..0] of Byte;
  75.     end;
  76. const
  77.      { error returns from waveio functions }
  78.      WIOERR_BASE         = 100;
  79.      WIOERR_NOERROR      = 0;
  80.      WIOERR_ERROR        = WIOERR_BASE+1;
  81.      WIOERR_BADHANDLE    = WIOERR_BASE+2;
  82.      WIOERR_BADFLAGS     = WIOERR_BASE+3;
  83.      WIOERR_BADPARAM     = WIOERR_BASE+4;
  84.      WIOERR_BADSIZE      = WIOERR_BASE+5;
  85.      WIOERR_FILEERROR    = WIOERR_BASE+6;
  86.      WIOERR_NOMEM        = WIOERR_BASE+7;
  87.      WIOERR_BADFILE  = WIOERR_BASE+8;
  88.      WIOERR_NODEVICE  = WIOERR_BASE+9;
  89.      WIOERR_BADFORMAT    = WIOERR_BASE+10;
  90.      WIOERR_ALLOCATED    = WIOERR_BASE+11;
  91.      WIOERR_NOTSUPPORTED = WIOERR_BASE+12;
  92. function  wioBytesPerSample(pwfx: PWaveFormatEx): integer;
  93. { 32 bit functions }
  94. function  wioBytesToSamples(pwfx: PWaveFormatEx; dwBytes: DWORD): DWORD;
  95. function  wioBytesToTime(pwfx: PWaveFormatEx; dwBytes: DWORD): DWORD;
  96. function  wioSamplesToBytes(pwfx: PWaveFormatEx; dwSamples: DWORD): DWORD;
  97. function  wioSamplesToTime(pwfx: PWaveFormatEx; dwSamples: DWORD): DWORD;
  98. function  wioTimeToSamples(pwfx: PWaveFormatEx; dwTime: DWORD): DWORD;
  99. function  wioTimeToBytes(pwfx: PWaveFormatEx; dwTime: DWORD): DWORD;
  100. { 64 bit functions }
  101. function  wioBytesToSamples64(pwfx: PWaveFormatEx; dwBytes: int64): int64;
  102. function  wioBytesToTime64(pwfx: PWaveFormatEx; dwBytes: int64): int64;
  103. function  wioSamplesToBytes64(pwfx: PWaveFormatEx; dwSamples: int64): int64;
  104. function  wioSamplesToTime64(pwfx: PWaveFormatEx; dwSamples: int64): int64;
  105. function  wioTimeToSamples64(pwfx: PWaveFormatEx; dwTime: int64): int64;
  106. function  wioTimeToBytes64(pwfx: PWaveFormatEx; dwTime: int64): int64;
  107. { lpwio functions }
  108. function  wioBytesToSamplesEx(lpwio: PWaveIOCB; dwBytes: DWORD): DWORD;
  109. function  wioBytesToTimeEx(lpwio: PWaveIOCB; dwBytes: DWORD): DWORD;
  110. function  wioSamplesToBytesEx(lpwio: PWaveIOCB; dwSamples: DWORD): DWORD;
  111. function  wioSamplesToTimeEx(lpwio: PWaveIOCB; dwSamples: DWORD): DWORD;
  112. function  wioTimeToSamplesEx(lpwio: PWaveIOCB; dwTime: DWORD): DWORD;
  113. function  wioTimeToBytesEx(lpwio: PWaveIOCB; dwTime: DWORD): DWORD;
  114. function  wioSizeOfWaveFormat(pwfx: PWaveFormatEx): integer;
  115. function  wioCopyWaveFormat(pwfx: PWaveFormatEx): PWaveFormatEx;
  116. procedure wioGetFormatName(pwfx: PWaveFormatEx; var FormatName: String);
  117. procedure wioGetFormat(pwfx: PWaveFormatEx; var Format: String);
  118. function  wioIsWaveFile(FilePath: TFileName; dwFlags: DWORD): Boolean;
  119. function  wioGetFullPathName(lpFilePath: PChar): Boolean;
  120. function  wioFileExists(lpFilePath: PChar): Boolean;
  121. function  wioFileDelete(lpFilePath: PChar): Boolean;
  122. procedure wioExtractPath(lpFilePath: PChar);
  123. function  wioFileCreateTemp(lpFilePath: PChar): Boolean;
  124. function  wioFileOpen(Var hmmio: THMMIO; Var ckRIFF: TMMCKINFO;
  125.                       Var HMem: THandle; lpFilePath: PChar;
  126.                       fccType: FourCC; dwFlags: DWORD): integer;
  127. procedure wioFileClose(Var hmmio: THMMIO; Var hMem: THandle);
  128. function  wioCreateFileInfo(Var lpwio: PWAVEIOCB; pwfx: PWaveFormatEx): integer;
  129. function  wioCopyFileInfo(lpwioDst, lpwioSrc: PWAVEIOCB): integer;
  130. function  wioBuildFileInfoFromMem(Var lpwio: PWaveIOCB; Memory: Pointer; MemSize: DWORD): Word;
  131. function  wioBuildFileInfoFromResource(Var lpwio: PWaveIOCB; ResourceName: PChar): Word;
  132. function  wioBuildFileInfoFromRAWEx(Var lpwio: PWaveIOCB; lpFileName: PChar; DataOffset: DWORD;
  133.                                     pwfx: PWaveFormatEx): integer;
  134. function  wioBuildFileInfoFromRAW(Var lpwio: PWaveIOCB; lpFileName: PChar;
  135.                                   DataOffset, BitLength, Channels, SampleRate: DWORD): integer;
  136. function  wioReadFileInfo(Var lpwio: PWAVEIOCB; lpFilePath: PChar;
  137.                           fccType: FourCC; dwFlags: DWORD): integer;
  138. function  wioWriteFileInfo(Var lpwio: PWAVEIOCB; lpFilePath: PChar): integer;
  139. function  wioFreeFileInfo(Var lpwio: PWAVEIOCB): integer;
  140. function  wioWaveCopyUselessChunks(lpwioSrc, lpwioDst: PWaveIOCB): integer;
  141. function  wioSetIOBufferSize(lpwio: PWaveIOCB; dwSize: integer): integer;
  142. function  wioWaveOpen(lpwio: PWaveIOCB): integer;
  143. function  wioWaveClose(lpwio: PWaveIOCB): integer;
  144. function  wioWaveLoadFile(lpFilePath: PChar; Var pwfx: PWaveFormatEx;
  145.                           Var Buffer: PChar; Var Size: DWORD): integer;
  146. function  wioWaveSaveFile(lpFilePath: PChar; pwfx: PWaveFormatEx;
  147.                           Buffer: PChar; Size: DWORD): integer;
  148. function  wioWaveSetFirstSample(lpwio: PWaveIOCB; dwSample: DWORD): integer;
  149. function  wioWaveSetLastSample(lpwio: PWaveIOCB; dwSample: DWORD): integer;
  150. function  wioWaveSetPosition(lpwio: PWaveIOCB; dwSample: DWORD): integer;
  151. function  wioWaveReadData(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  152. function  wioWaveReadDataDirect(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  153. function  wioWaveReadSamples(lpwio: PWaveIOCB; Buffer: PChar; nSamples: DWORD): DWORD;
  154. function  wioWaveWriteData(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  155. function  wioWaveWriteDataDirect(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  156. function  wioWaveWriteSamples(lpwio: PWaveIOCB; Buffer: PChar; nSamples: DWORD): DWORD;
  157. implementation
  158. Uses
  159.     MMMath,
  160.     MMMulDiv,
  161.     MMPCMSup;
  162. {$DEFINE ROUND_UP}
  163. {*************************************************************************}
  164. {*                                                                       *}
  165. {*  DESCRIPTION:                                                         *}
  166. {*      calculate the bytes per sample from the actual settings.         *)
  167. {*                                                                       *}
  168. {*************************************************************************}
  169. function wioBytesPerSample(pwfx: PWaveFormatEx): integer;
  170. begin
  171.      Result := wioSamplesToBytes(pwfx, 1);
  172. end;
  173. {*************************************************************************}
  174. {*                                                                       *}
  175. {*  DESCRIPTION:                                                         *}
  176. {*      convert a byte offset into a sample offset.                      *}
  177. {*                                                                       *}
  178. {*      dwSamples = (dwBytes / nAvgBytesPerSec) * nSamplesPerSec         *}
  179. {*                                                                       *}
  180. {*************************************************************************}
  181. function wioBytesToSamples(pwfx: PWaveFormatEx; dwBytes: DWORD): DWORD;
  182. begin
  183.      Result := muldiv32RN(dwBytes,
  184.                           pwfx^.nSamplesPerSec,
  185.                           pwfx^.nAvgBytesPerSec);
  186. end;
  187. {*************************************************************************}
  188. {*                                                                       *}
  189. {*  DESCRIPTION:                                                         *}
  190. {*      convert a byte offset into a time offset in milliseconds.        *}
  191. {*                                                                       *}
  192. (*      dwTime = (dwBytes / nAvgBytesPerSec) * 1000                      *)
  193. {*                                                                       *}
  194. {*************************************************************************}
  195. function wioBytesToTime(pwfx: PWaveFormatEx; dwBytes: DWORD): DWORD;
  196. begin
  197.      Result := muldiv32RN(dwBytes, 1000, pwfx^.nAvgBytesPerSec);
  198. end;
  199. {*************************************************************************}
  200. {*                                                                       *}
  201. {*  DESCRIPTION:                                                         *}
  202. {*     convert a sample offset into a byte offset, with correct alignment*}
  203. {*     to nBlockAlign.                                                   *}
  204. {*                                                                       *}
  205. {*     dwBytes = (dwSamples / nSamplesPerSec) * nBytesPerSec             *}
  206. {*                                                                       *}
  207. {*************************************************************************}
  208. function wioSamplesToBytes(pwfx: PWaveFormatEx; dwSamples: DWORD): DWORD;
  209. begin
  210.      Result := muldiv32RN(dwSamples,
  211.                           pwfx^.nAvgBytesPerSec,
  212.                           pwfx^.nSamplesPerSec);
  213.      { now align the byte offset to nBlockAlign }
  214. {$IFDEF ROUND_UP}
  215.      Result := ((Result + pwfx^.nBlockAlign-1) div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  216. {$ELSE}
  217.      Result := (Result div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  218. {$ENDIF}
  219. end;
  220. {*************************************************************************}
  221. {*                                                                       *}
  222. {*  DESCRIPTION:                                                         *}
  223. {*      convert a sample offset into a time offset in milliseconds.      *}
  224. {*                                                                       *}
  225. {*      dwTime = (dwSamples / nSamplesPerSec) * 1000                     *}
  226. {*                                                                       *}
  227. {*************************************************************************}
  228. function wioSamplesToTime(pwfx: PWaveFormatEx; dwSamples: DWORD): DWORD;
  229. begin
  230.      Result := muldiv32RN(dwSamples, 1000, pwfx^.nSamplesPerSec);
  231. end;
  232. {*************************************************************************}
  233. {*                                                                       *}
  234. {*  DESCRIPTION:                                                         *}
  235. {*      convert a time index in milliseconds to a sample offset.         *}
  236. {*                                                                       *}
  237. {*      dwSamples = (dwTime / 1000) * nSamplesPerSec                     *}
  238. {*                                                                       *}
  239. {*************************************************************************}
  240. function wioTimeToSamples(pwfx: PWaveFormatEx; dwTime: DWORD): DWORD;
  241. begin
  242.      Result := muldiv32RN(dwTime, pwfx^.nSamplesPerSec, 1000);
  243. end;
  244. {*************************************************************************}
  245. {*                                                                       *}
  246. {*  DESCRIPTION:                                                         *}
  247. {*      convert a time index in milliseconds to a byte offset, with      *)
  248. (*      correct alignment to nBlockAlign.                           .    *)
  249. {*                                                                       *}
  250. {*      dwBytes = ((dwTime / 1000) * nAvgBytesPerSec)                    *}
  251. {*                                                                       *}
  252. {*************************************************************************}
  253. function  wioTimeToBytes(pwfx: PWaveFormatEx; dwTime: DWORD): DWORD;
  254. begin
  255.      Result := muldiv32RN(dwTime, pwfx^.nAvgBytesPerSec, 1000);
  256.      { now align the byte offset to nBlockAlign }
  257. {$IFDEF ROUND_UP}
  258.      Result := ((Result + pwfx^.nBlockAlign-1) div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  259. {$ELSE}
  260.      Result := (Result div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  261. {$ENDIF}
  262. end;
  263. {*************************************************************************}
  264. {*                                                                       *}
  265. {*  DESCRIPTION:                                                         *}
  266. {*      convert a byte offset into a sample offset. (64 bit)             *}
  267. {*                                                                       *}
  268. {*      dwSamples = (dwBytes / nAvgBytesPerSec) * nSamplesPerSec         *}
  269. {*                                                                       *}
  270. {*************************************************************************}
  271. function wioBytesToSamples64(pwfx: PWaveFormatEx; dwBytes: int64): int64;
  272. begin
  273.      Result := MulDiv64(dwBytes,
  274.                         pwfx^.nSamplesPerSec,
  275.                         pwfx^.nAvgBytesPerSec);
  276. end;
  277. {*************************************************************************}
  278. {*                                                                       *}
  279. {*  DESCRIPTION:                                                         *}
  280. {*      convert a byte offset into a time offset in milliseconds.(64 bit)*}
  281. {*                                                                       *}
  282. (*      dwTime = (dwBytes / nAvgBytesPerSec) * 1000                      *)
  283. {*                                                                       *}
  284. {*************************************************************************}
  285. function wioBytesToTime64(pwfx: PWaveFormatEx; dwBytes: int64): int64;
  286. begin
  287.      Result := MulDiv64(dwBytes, 1000, pwfx^.nAvgBytesPerSec);
  288. end;
  289. {*************************************************************************}
  290. {*                                                                       *}
  291. {*  DESCRIPTION:                                                         *}
  292. {*     convert a sample offset into a byte offset, with correct alignment*}
  293. {*     to nBlockAlign.                                                   *}
  294. {*                                                                       *}
  295. {*     dwBytes = (dwSamples / nSamplesPerSec) * nBytesPerSec             *}
  296. {*                                                                       *}
  297. {*************************************************************************}
  298. function wioSamplesToBytes64(pwfx: PWaveFormatEx; dwSamples: int64): int64;
  299. {$IFNDEF DELPHI4}
  300. var
  301.    Temp: int64;
  302. {$ENDIF}
  303. begin
  304.      Result := muldiv64(dwSamples,
  305.                         pwfx^.nAvgBytesPerSec,
  306.                         pwfx^.nSamplesPerSec);
  307.      { now align the byte offset to nBlockAlign }
  308. {$IFDEF ROUND_UP}
  309.      {$IFDEF DELPHI4}
  310.      Result := ((Result + pwfx^.nBlockAlign-1) div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  311.      {$ELSE}
  312.      Temp := Result + pwfx^.nBlockAlign-1;
  313.      Result := ((Temp/pwfx^.nBlockAlign)-ModR(Temp,pwfx^.nBlockAlign))* pwfx^.nBlockAlign;
  314.      {$ENDIF}
  315. {$ELSE}
  316.      {$IFDEF DELPHI4}
  317.      Result := (Result div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  318.      {$ELSE}
  319.      Result := ((Result / pwfx^.nBlockAlign)-ModR(Result,pwfx^.nBlockAlign)) * pwfx^.nBlockAlign;
  320.      {$ENDIF}
  321. {$ENDIF}
  322. end;
  323. {*************************************************************************}
  324. {*                                                                       *}
  325. {*  DESCRIPTION:                                                         *}
  326. {*      convert a sample offset into a time offset in milliseconds.      *}
  327. {*                                                                       *}
  328. {*      dwTime = (dwSamples / nSamplesPerSec) * 1000                     *}
  329. {*                                                                       *}
  330. {*************************************************************************}
  331. function wioSamplesToTime64(pwfx: PWaveFormatEx; dwSamples: int64): int64;
  332. begin
  333.      Result := muldiv64(dwSamples, 1000, pwfx^.nSamplesPerSec);
  334. end;
  335. {*************************************************************************}
  336. {*                                                                       *}
  337. {*  DESCRIPTION:                                                         *}
  338. {*      convert a time index in milliseconds to a sample offset.         *}
  339. {*                                                                       *}
  340. {*      dwSamples = (dwTime / 1000) * nSamplesPerSec                     *}
  341. {*                                                                       *}
  342. {*************************************************************************}
  343. function wioTimeToSamples64(pwfx: PWaveFormatEx; dwTime: int64): int64;
  344. begin
  345.      Result := muldiv64(dwTime, pwfx^.nSamplesPerSec, 1000);
  346. end;
  347. {*************************************************************************}
  348. {*                                                                       *}
  349. {*  DESCRIPTION:                                                         *}
  350. {*      convert a time index in milliseconds to a byte offset, with      *)
  351. (*      correct alignment to nBlockAlign.                           .    *)
  352. {*                                                                       *}
  353. {*      dwBytes = ((dwTime / 1000) * nBytesPerSec)                       *}
  354. {*                                                                       *}
  355. {*************************************************************************}
  356. function  wioTimeToBytes64(pwfx: PWaveFormatEx; dwTime: int64): int64;
  357. {$IFNDEF DELPHI4}
  358. var
  359.    Temp: int64;
  360. {$ENDIf}
  361. begin
  362.      Result := muldiv64(dwTime, pwfx^.nAvgBytesPerSec, 1000);
  363.      { now align the byte offset to nBlockAlign }
  364. {$IFDEF ROUND_UP}
  365.      {$IFDEF DELPHI4}
  366.      Result := ((Result + pwfx^.nBlockAlign-1) div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  367.      {$ELSE}
  368.      Temp := Result + pwfx^.nBlockAlign-1;
  369.      Result := ((Temp/pwfx^.nBlockAlign)-ModR(Temp,pwfx^.nBlockAlign)) * pwfx^.nBlockAlign;
  370.      {$ENDIF}
  371. {$ELSE}
  372.      {$IFDEF DELPHI4}
  373.      Result := (Result div pwfx^.nBlockAlign) * pwfx^.nBlockAlign;
  374.      {$ELSE}
  375.      Result := ((Result/pwfx^.nBlockAlign)-ModR(Result,pwfx^.nBlockAlign)) * pwfx^.nBlockAlign;
  376.      {$ENDIF}
  377. {$ENDIF}
  378. end;
  379. {*************************************************************************}
  380. {*                                                                       *}
  381. {*  DESCRIPTION:                                                         *}
  382. {*      calculate the bytes per sample from the actual settings.         *)
  383. {*                                                                       *}
  384. {*************************************************************************}
  385. function wioBytesPerSampleEx(lpwio: PWaveIOCB): integer;
  386. begin
  387.      Result := wioSamplesToBytesEx(lpwio, 1);
  388. end;
  389. {*************************************************************************}
  390. {*                                                                       *}
  391. {*  DESCRIPTION:                                                         *}
  392. {*      convert a byte offset into a sample offset.                      *}
  393. {*                                                                       *}
  394. {*      dwSamples = (dwBytes / nAvgBytesPerSec) * nSamplesPerSec         *}
  395. {*                                                                       *}
  396. {*************************************************************************}
  397. function wioBytesToSamplesEx(lpwio: PWaveIOCB; dwBytes: DWORD): DWORD;
  398. begin
  399.      if (lpwio^.fAvgBytesPerSec <> 0) then
  400.      begin
  401.         Result := Round((dwBytes*lpwio^.wfx.nSamplesPerSec)/lpwio^.fAvgBytesPerSec);
  402.      end
  403.      else Result := wioBytesToSamples(@lpwio^.wfx,dwBytes);
  404. end;
  405. {*************************************************************************}
  406. {*                                                                       *}
  407. {*  DESCRIPTION:                                                         *}
  408. {*      convert a byte offset into a time offset in milliseconds.        *}
  409. {*                                                                       *}
  410. (*      dwTime = (dwBytes / nAvgBytesPerSec) * 1000                      *)
  411. {*                                                                       *}
  412. {*************************************************************************}
  413. function wioBytesToTimeEx(lpwio: PWaveIOCB; dwBytes: DWORD): DWORD;
  414. begin
  415.      if (lpwio^.fAvgBytesPerSec <> 0) then
  416.      begin
  417.         Result := Round((dwBytes*1000)/lpwio^.fAvgBytesPerSec);
  418.      end
  419.      else Result := wioBytesToTime(@lpwio^.wfx,dwBytes);
  420. end;
  421. {*************************************************************************}
  422. {*                                                                       *}
  423. {*  DESCRIPTION:                                                         *}
  424. {*     convert a sample offset into a byte offset, with correct alignment*}
  425. {*     to nBlockAlign.                                                   *}
  426. {*                                                                       *}
  427. {*     dwBytes = (dwSamples / nSamplesPerSec) * nBytesPerSec             *}
  428. {*                                                                       *}
  429. {*************************************************************************}
  430. function wioSamplesToBytesEx(lpwio: PWaveIOCB; dwSamples: DWORD): DWORD;
  431. begin
  432.      if (lpwio^.fAvgBytesPerSec <> 0) then
  433.      begin
  434.         Result := Round((dwSamples*lpwio^.fAvgBytesPerSec)/lpwio^.wfx.nSamplesPerSec);
  435.         { now align the byte offset to nBlockAlign }
  436.         {$IFDEF ROUND_UP}
  437.         Result := ((Result + lpwio^.wfx.nBlockAlign-1) div lpwio^.wfx.nBlockAlign) * lpwio^.wfx.nBlockAlign;
  438.         {$ELSE}
  439.         Result := (Result div lpwio^.wfx.nBlockAlign) * lpwio^.wfx.nBlockAlign;
  440.         {$ENDIF}
  441.      end
  442.      else Result := wioSamplesToBytes(@lpwio^.wfx,dwSamples);
  443. end;
  444. {*************************************************************************}
  445. {*                                                                       *}
  446. {*  DESCRIPTION:                                                         *}
  447. {*      convert a sample offset into a time offset in milliseconds.      *}
  448. {*                                                                       *}
  449. {*      dwTime = (dwSamples / nSamplesPerSec) * 1000                     *}
  450. {*                                                                       *}
  451. {*************************************************************************}
  452. function wioSamplesToTimeEx(lpwio: PWaveIOCB; dwSamples: DWORD): DWORD;
  453. begin
  454.      if (lpwio^.fAvgBytesPerSec <> 0) then
  455.      begin
  456.         Result := Round((dwSamples*1000)/lpwio^.wfx.nSamplesPerSec);
  457.      end
  458.      else Result := wioSamplesToTime(@lpwio^.wfx,dwSamples);
  459. end;
  460. {*************************************************************************}
  461. {*                                                                       *}
  462. {*  DESCRIPTION:                                                         *}
  463. {*      convert a time index in milliseconds to a sample offset.         *}
  464. {*                                                                       *}
  465. {*      dwSamples = (dwTime / 1000) * nSamplesPerSec                     *}
  466. {*                                                                       *}
  467. {*************************************************************************}
  468. function wioTimeToSamplesEx(lpwio: PWaveIOCB; dwTime: DWORD): DWORD;
  469. begin
  470.      if (lpwio^.fAvgBytesPerSec <> 0) then
  471.      begin
  472.         Result := Round((dwTime*lpwio^.wfx.nSamplesPerSec)/1000);
  473.      end
  474.      else Result := wioTimeToSamples(@lpwio^.wfx,dwTime);
  475. end;
  476. {*************************************************************************}
  477. {*                                                                       *}
  478. {*  DESCRIPTION:                                                         *}
  479. {*      convert a time index in milliseconds to a byte offset, with      *)
  480. (*      correct alignment to nBlockAlign.                           .    *)
  481. {*                                                                       *}
  482. {*      dwBytes = ((dwTime / 1000) * nAvgBytesPerSec)                    *}
  483. {*                                                                       *}
  484. {*************************************************************************}
  485. function  wioTimeToBytesEx(lpwio: PWaveIOCB; dwTime: DWORD): DWORD;
  486. begin
  487.      if (lpwio^.fAvgBytesPerSec <> 0) then
  488.      begin
  489.         Result := Round((dwTime*lpwio^.fAvgBytesPerSec)/1000);
  490.         { now align the byte offset to nBlockAlign }
  491.         {$IFDEF ROUND_UP}
  492.         Result := ((Result + lpwio^.wfx.nBlockAlign-1) div lpwio^.wfx.nBlockAlign) * lpwio^.wfx.nBlockAlign;
  493.         {$ELSE}
  494.         Result := (Result div lpwio^.wfx.nBlockAlign) * lpwio^.wfx.nBlockAlign;
  495.         {$ENDIF}
  496.      end
  497.      else Result := wioTimeToBytes(@lpwio^.wfx, dwTime);
  498. end;
  499. {*************************************************************************}
  500. {*                                                                       *}
  501. {*  DESCRIPTION:                                                         *}
  502. {*      returns the size of the wave format structure pwfx               *}
  503. {*                                                                       *}
  504. {*************************************************************************}
  505. function wioSizeOfWaveFormat(pwfx: PWaveFormatEx): integer;
  506. begin
  507.    if (pwfx <> nil) then
  508.    begin
  509.       if pwfx^.wFormatTag = WAVE_FORMAT_PCM then
  510.          Result := sizeOf(TWaveFormatEx)
  511.       else
  512.          Result := sizeOf(TWaveFormatEx)+pwfx^.cbSize
  513.    end
  514.    else Result := 0;
  515. end;
  516. {*************************************************************************}
  517. {*                                                                       *}
  518. {*  DESCRIPTION:                                                         *}
  519. {*      duplicates the wave format structure pwfx                        *}
  520. {*                                                                       *}
  521. {*************************************************************************}
  522. function wioCopyWaveFormat(pwfx: PWaveFormatEx): PWaveFormatEx;
  523. var
  524.    Size: integer;
  525. begin
  526.    Result := nil;
  527.    if (pwfx <> nil) then
  528.    begin
  529.       Size := wioSizeOfWaveFormat(pwfx);
  530.       if (Size > 0) then
  531.       begin
  532.          { get the memory }
  533.          Result := GlobalAllocMem(Size);
  534.          { copy the WaveFormatEx struc }
  535.          Move(pwfx^, Result^, Size);
  536.          if (Result^.wFormatTag = 1) then
  537.              Result^.cbSize := 0;
  538.       end;
  539.    end;
  540. end;
  541. {*************************************************************************}
  542. type
  543.     TStrFormat = packed record
  544.        szformat: String;
  545.        wFormat : Word;
  546.     end;
  547. const
  548.     Formats: array[0..38] of TStrFormat = (
  549.     (szformat:'Unknown'                    ; wFormat: WAVE_FORMAT_UNKNOWN),
  550.     (szformat:'PCM'                        ; wFormat: WAVE_FORMAT_PCM),
  551.     (szformat:'PCM 32'                     ; wFormat: WAVE_FORMAT_PCM32),
  552.     (szformat:'Microsoft ADPCM'            ; wFormat: WAVE_FORMAT_ADPCM),
  553.     (szformat:'Mediavision''s ADPCM'       ; wFormat: WAVE_FORMAT_MEDIAVISION_ADPCM),
  554.     (szformat:'IBM CVSD'                   ; wFormat: WAVE_FORMAT_IBM_CVSD),
  555.     (szformat:'CCITT A-Law'                ; wFormat: WAVE_FORMAT_ALAW),
  556.     (szformat:'CCITT mu-Law'               ; wFormat: WAVE_FORMAT_MULAW),
  557.     (szformat:'OKI ADPCM'                  ; wFormat: WAVE_FORMAT_OKI_ADPCM),
  558.     (szformat:'IMA ADPCM'                  ; wFormat: WAVE_FORMAT_IMA_ADPCM),
  559.     (szformat:'DVI ADPCM'                  ; wFormat: WAVE_FORMAT_DVI_ADPCM),
  560.     (szformat:'Mediaspace''s ADPCM'        ; wFormat: WAVE_FORMAT_MEDIASPACE_ADPCM),
  561.     (szformat:'Sierra''s ADPCM'            ; wFormat: WAVE_FORMAT_SIERRA_ADPCM),
  562.     (szformat:'CCITT G.723 ADPCM'          ; wFormat: WAVE_FORMAT_G723_ADPCM),
  563.     (szformat:'Digisound DIGISTD'          ; wFormat: WAVE_FORMAT_DIGISTD),
  564.     (szformat:'Digisound DIGIFIX'          ; wFormat: WAVE_FORMAT_DIGIFIX),
  565.     (szformat:'Dialogic OKI ADPCM'         ; wFormat: WAVE_FORMAT_DIALOGIC_OKI_ADPCM),
  566.     (szformat:'Yamaha ADPCM'               ; wFormat: WAVE_FORMAT_YAMAHA_ADPCM),
  567.     (szformat:'Sonarc'                     ; wFormat: WAVE_FORMAT_SONARC),
  568.     (szformat:'DSP Group''s Truespeech'    ; wFormat: WAVE_FORMAT_DSPGROUP_TRUESPEECH),
  569.     (szformat:'Echo SC1'                   ; wFormat: WAVE_FORMAT_ECHOSC1),
  570.     (szformat:'Audiofile AF36'             ; wFormat: WAVE_FORMAT_AUDIOFILE_AF36),
  571.     (szformat:'Audio Processing Technology'; wFormat: WAVE_FORMAT_APTX),
  572.     (szformat:'Audiofile AF10'             ; wFormat: WAVE_FORMAT_AUDIOFILE_AF10),
  573.     (szformat:'Dolby AC2'                  ; wFormat: WAVE_FORMAT_DOLBY_AC2),
  574.     (szformat:'Dolby AC2'                  ; wFormat: WAVE_FORMAT_DOLBY_AC2_REVA),
  575.     (szformat:'GSM 6.10'                   ; wFormat: WAVE_FORMAT_GSM610),
  576.     (szformat:'Antex ADPCME'               ; wFormat: WAVE_FORMAT_ANTEX_ADPCME),
  577.     (szformat:'CS IMA ADPCM'               ; wFormat: WAVE_FORMAT_CS_IMAADPCM),
  578.     (szformat:'CCITT G.721 ADPCM'          ; wFormat: WAVE_FORMAT_G721_ADPCM),
  579.     (szformat:'MPEG 1'                     ; wFormat: WAVE_FORMAT_MPEG),
  580.     (szformat:'MPEG Layer-3'               ; wFormat: WAVE_FORMAT_MPEG_LAYER3),
  581.     (szformat:'Creative''s ADPCM'          ; wFormat: WAVE_FORMAT_CREATIVE_ADPCM),
  582.     (szformat:'Olivetti''s ADPCM'          ; wFormat: WAVE_FORMAT_OLIADPCM),
  583.     (szFormat:'CDI-C'                      ; wFormat: WAVE_FORMAT_CDIC),
  584.     (szFormat:'CDI-B'                      ; wFormat: WAVE_FORMAT_CDIB),
  585.     (szFormat:'Antex-DVI-OKI ADPCME'       ; wFormat: WAVE_FORMAT_ADPCME),
  586.     (szformat:'*DEVELOPMENT ONLY TAG*'     ; wFormat: WAVE_FORMAT_DEVELOPMENT),
  587.     (szformat:''                           ; wFormat: 0));
  588. {*************************************************************************}
  589. procedure wioGetFormatName(pwfx: PWaveFormatEx; var FormatName: String);
  590. Var
  591.    i: integer;
  592. begin
  593.      if (pwfx <> Nil) then
  594.      begin
  595.           i := 0;
  596.           while (formats[i].szformat <> '') do
  597.           begin
  598.        if (formats[i].wFormat = pwfx^.wFormatTag) then
  599.        begin
  600.             FormatName := formats[i].szformat;
  601.                     exit;
  602.                end;
  603.                inc(i);
  604.           end;
  605.      end;
  606.      FormatName := 'Unknown';
  607. end;
  608. {*************************************************************************}
  609. procedure wioGetFormat(pwfx: PWaveFormatEx; var Format: String);
  610. const
  611.      gszIntl        = 'Intl';
  612.      gszIntlList    = 'sList';
  613.      gszIntlDecimal = 'sDecimal';
  614.      gchIntlList    : char = ',';
  615.      gchIntlDecimal : char = '.';
  616. var
  617.    aBuf    : array[0..255] of char;
  618.    ach     : array[0..1] of char;
  619.    Channels: array[0..24] of char;
  620.    Bits    : word;
  621. begin
  622.      if (pwfx <> Nil) then
  623.      begin
  624.         ach[0] := gchIntlList;
  625.         ach[1] := #0;
  626.         GetProfileString(gszIntl, gszIntlList, ach, ach, sizeof(ach));
  627.         gchIntlList := ach[0];
  628.         ach[0] := gchIntlDecimal;
  629.         ach[1] := #0;
  630.         GetProfileString(gszIntl, gszIntlDecimal, ach, ach, sizeof(ach));
  631.         gchIntlDecimal := ach[0];
  632.         { compute the bit depth--this _should_ be the same as }
  633.         { wBitsPerSample, but isn't always...                 }
  634.         Bits := (pwfx^.nAvgBytesPerSec * 8 div
  635.                  pwfx^.nSamplesPerSec div pwfx^.nChannels);
  636.         if (pwfx^.nChannels = 1) or (pwfx^.nChannels = 2) then
  637.         begin
  638.            if (pwfx^.nChannels = 1)then
  639.                StrCopy(Channels, 'Mono')
  640.            else
  641.                StrCopy(Channels, 'Stereo');
  642.            StrFmt(aBuf,'%d%s%.03d kHz%s %d Bit%s %s',
  643.                        [pwfx^.nSamplesPerSec div 1000, gchIntlDecimal,
  644.                         pwfx^.nSamplesPerSec mod 1000, gchIntlList,
  645.                         Bits, gchIntlList, Channels]);
  646.         end
  647.         else
  648.         begin
  649.            StrFmt(aBuf,'%d%s%.03d kHz%s %d Bit%s %d Channels',
  650.                   [pwfx^.nSamplesPerSec div 1000, gchIntlDecimal,
  651.                    pwfx^.nSamplesPerSec mod 1000, gchIntlList,
  652.                    Bits, gchIntlList, pwfx^.nChannels]);
  653.         end;
  654.         Format := StrPas(aBuf);
  655.      end
  656.      else Format := 'Unknown';
  657. end;
  658. {**************************************************************************}
  659. function wioIsWaveFile(FilePath: TFileName; dwFlags: DWORD): Boolean;
  660. Var
  661.    aBuf: PChar;
  662.    lpwio: PWAVEIOCB;
  663. begin
  664.      Result := False;
  665.      if FilePath <> '' then
  666.      begin
  667.           aBuf := StrAlloc(Length(FilePath)+1);
  668.           try
  669.              StrPCopy(aBuf, FilePath);
  670.              if wioReadFileInfo(lpwio, aBuf,
  671.                                 mmioFOURCC('W', 'A', 'V', 'E'),
  672.                                 dwFlags) = 0 then
  673.                 Result := True;
  674.           finally
  675.              wioFreeFileInfo(lpwio);
  676.              StrDispose(aBuf);
  677.           end;
  678.      end;
  679. end;
  680. {**************************************************************************}
  681. function wioGetFullPathName(lpFilePath: PChar): Boolean;
  682. begin
  683.    { return a full path for this file }
  684.    Result := mmioOpen(lpFilePath, Nil, MMIO_PARSE) <> 0;
  685. end;
  686. {**************************************************************************}
  687. function wioFileExists(lpFilePath: PChar): Boolean;
  688. begin
  689.      Result := mmioOpen(lpFilePath, Nil, MMIO_EXIST) <> 0;
  690. end;
  691. {**************************************************************************}
  692. function wioFileDelete(lpFilePath: PChar): Boolean;
  693. begin
  694.      Result := mmioOpen(lpFilePath, Nil, MMIO_DELETE) <> 0;
  695. end;
  696. {**************************************************************************}
  697. procedure wioExtractPath(lpFilePath: PChar);
  698. var
  699.   i: Integer;
  700. begin
  701.    i := StrLen(lpFilePath);
  702.    while (i > 0) and not (lpFilePath[i] in ['', ':']) do
  703.    begin
  704.       lpFilePath[i] := #0;
  705.       dec(i);
  706.    end;
  707. end;
  708. {**************************************************************************}
  709. function wioFileCreateTemp(lpFilePath: PChar): Boolean;
  710. begin
  711.      {$IFDEF WIN32}
  712.      if (lpFilePath = '') or (lpFilePath[0] = #0) then
  713.      begin
  714.         GetTempPath(MAX_PATH-1,lpFilePath);
  715.      end;
  716.      {$ENDIF}
  717.      { make sure we have a full pathname }
  718.      wioGetFullPathName(lpFilePath);
  719. {$IFDEF WIN32}
  720.      { extract the filename }
  721.      wioExtractPath(lpFilePath);
  722.      { create the temp file }
  723.      Result := GetTempFileName(lpFilePath,
  724.                                'w'#0,
  725.                                Random(256)+1,
  726.                                lpFilePath) <> 0;
  727. {$ELSE}
  728.      { get the drive letter }
  729.      StrLCopy(lpFilePath, StrUpper(lpFilePath), 2);
  730.      { create the temp file }
  731.      Result := GetTempFileName(Char(Byte(UpCase(lpFilePath[0]))or TF_FORCEDRIVE),
  732.                                'w'#0, 0, lpFilePath) <> 0;
  733. {$ENDIF}
  734.      { return a full path for this file }
  735.      if Result then
  736.      begin
  737.         wioGetFullPathName(lpFilePath);
  738.         wioFileDelete(lpFilePath);
  739.      end;
  740. end;
  741. {**************************************************************************}
  742. procedure wioFileClose(Var hmmio: THMMIO; Var hMem: THandle);
  743. begin
  744.      if (hMem <> 0) then
  745.      begin
  746.           UnlockResource(hMem);
  747.   FreeResource(hMem);
  748.           hMem := 0;
  749.      end;
  750.      if (hmmio <> 0) then mmioClose(hmmio, 0);
  751.      hmmio := 0;
  752. end;
  753. (**************************************************************************)
  754. function wioFileOpen(Var hmmio: THMMIO;
  755.                      Var ckRIFF: TMMCKINFO;
  756.                      Var HMem: THandle;
  757.                      lpFilePath: PChar;
  758.                      fccType: FourCC;
  759.                      dwFlags: DWORD): integer;
  760. Label ERROR_OPEN_WAVE;
  761. Var
  762.    HRsrc: THandle;
  763.    mmioInfo: TMMIOINFO;
  764. begin
  765.      { default our error return (assume the worst) }
  766.      Result := WIOERR_FILEERROR;
  767.      HMem := 0;
  768.      { first try to open the file, etc.. open the given file for reading }
  769.      { using buffered I/O                                                }
  770.      if (dwFlags AND RIFF_RESOURCE <> 0) then
  771.      begin
  772.   HRsrc := FindResource(HInstance, lpFilePath, 'WAVE');
  773.           HMem := LoadResource(HInstance, HRsrc);
  774.           if HMem = 0 then
  775.              goto ERROR_OPEN_WAVE;
  776.           FillChar(mmioInfo, sizeOf(TMMIOINFO), 0);
  777.           mmioInfo.pchBuffer := LockResource(HMem);
  778.   if mmioInfo.pchBuffer = Nil then
  779.              goto ERROR_OPEN_WAVE;
  780. {$IFDEF WIN32}
  781.           mmioInfo.cchBuffer := SizeofResource(HInstance,HRsrc);
  782. {$ELSE}
  783.   mmioInfo.cchBuffer := GlobalSize(HMem);
  784. {$ENDIF}
  785.   mmioInfo.fccIOProc := FOURCC_MEM;
  786.   mmioInfo.adwInfo[0] := 0;
  787.           hmmio := mmioOpen(Nil, @mmioInfo, MMIO_READ OR MMIO_ALLOCBUF);
  788.           if (hmmio = 0) then
  789.              goto ERROR_OPEN_WAVE;
  790.      end
  791.      else if (dwFlags AND RIFF_MEMORY <> 0) then
  792.      begin
  793.           move(lpFilePath^, mmioInfo, sizeOf(TMMIOINFO));
  794.           mmioInfo.fccIOProc := FOURCC_MEM;
  795.           mmioInfo.adwInfo[0] := 0;
  796.           hmmio := mmioOpen(Nil, @mmioInfo, MMIO_READ OR MMIO_ALLOCBUF);
  797.           if (hmmio = 0) then
  798.              goto ERROR_OPEN_WAVE;
  799.      end
  800.      else { Open the given file for reading using buffered I/O. }
  801.      begin
  802.           if (FileGetAttr(StrPas(lpFilePath)) and faReadOnly = 0) then
  803.           begin
  804.              hmmio := mmioOpen(lpFilePath, Nil, MMIO_READWRITE OR MMIO_ALLOCBUF);
  805.              if (hmmio = 0) then
  806.                  hmmio := mmioOpen(lpFilePath, Nil, MMIO_READ OR MMIO_ALLOCBUF);
  807.           end
  808.           else
  809.              hmmio := mmioOpen(lpFilePath, Nil, MMIO_READ OR MMIO_ALLOCBUF);
  810.           if (hmmio = 0) then
  811.               goto ERROR_OPEN_WAVE;
  812.      end;
  813.      if mmioDescend(hmmio, @ckRIFF, Nil, 0) <> 0 then
  814.         goto ERROR_OPEN_WAVE;
  815.      if (ckRIFF.ckid <> FOURCC_RIFF) or (ckRIFF.fccType <> fccType) then
  816.         goto ERROR_OPEN_WAVE;
  817.      Result := WIOERR_NOERROR;
  818.      exit;
  819. ERROR_OPEN_WAVE:
  820.      wioFileClose(hmmio, hMem);
  821. end;
  822. {**************************************************************************}
  823. function wioReadFileInfo(Var lpwio: PWAVEIOCB; lpFilePath: PChar;
  824.                          fccType: FourCC; dwFlags: DWORD): integer;
  825. Label ERROR_READING_WAVE;
  826. Var
  827.    hmmio: THMMIO;
  828.    hMem : THandle;
  829.    wio: TWAVEIOCB;
  830.    ck,ckRIFF: TMMCKINFO;
  831.    dw: Longint;
  832.    TempRes: integer;
  833.    CheckDataSize: Boolean;
  834.    NextOffset: DWORD;
  835.    hasFormat,hasData: Boolean;
  836. begin
  837.      { default our error return (assume the worst) }
  838.      Result := WIOERR_FILEERROR;
  839.      lpwio := Nil;
  840.      { first try to open the file, etc.. open the given file for reading }
  841.      { using buffered I/O                                                }
  842.      if (wioFileOpen(hmmio, ckRIFF, hMem, lpFilePath, fccType, dwFlags) <> 0) OR (hmmio = 0) then
  843.         goto ERROR_READING_WAVE;
  844.      FillChar(wio, sizeof(wio), 0);
  845.      { Save the filename or the memory/resource mmioInfo structure }
  846.      if (dwFlags = RIFF_MEMORY) then
  847.      begin
  848.           wio.lpFilePath := StrAlloc(sizeOf(TMMIOINFO)+1);
  849.           move(lpFilePath^, wio.lpFilePath^, sizeOf(TMMIOINFO));
  850.      end
  851.      else wio.lpFilePath := StrNew(lpFilePath);
  852.     { get the file size }
  853.      wio.dwFileSize := mmioSeek(hmmio, 0, SEEK_END);
  854.      if (wio.dwFileSize = $FFFFFFFF) then
  855.         goto ERROR_READING_WAVE;
  856.      { return to RIFF chunk }
  857.      if mmioSeek(hmmio, ckRIFF.dwDataOffset + sizeOf(FOURCC), SEEK_SET) = -1 then
  858.         goto ERROR_READING_WAVE;
  859.      { quickly check for corrupt RIFF file--don't ascend past end!  }
  860.      if (ckRIFF.dwDataOffset + ckRIFF.cksize > wio.dwFileSize) then
  861.      begin
  862.         ckRIFF.ckSize := wio.dwFileSize-ckRIFF.dwDataOffset;
  863.         {goto ERROR_READING_WAVE;}
  864.      end;
  865.      { we found a WAVE chunk--now go through and get all subchunks that }
  866.      { we know how to deal with...                                      }
  867.      wio.dwDataSamples  := $FFFFFFFF;
  868.      TempRes := RiffInitINFO(wio.lpInfo);
  869.      if TempRes <> 0 then
  870.      begin
  871.         Result := TempRes;
  872.           goto ERROR_READING_WAVE;
  873.      end;
  874.      TempRes := RiffInitDISP(wio.lpDisp);
  875.      if TempRes <> 0 then
  876.      begin
  877.         Result := TempRes;
  878.           goto ERROR_READING_WAVE;
  879.      end;
  880.      CheckDataSize := False;
  881.      NextOffset := wio.dwFileSize;
  882.      hasFormat := False;
  883.      hasData   := False;
  884.      while mmioDescend(hmmio, @ck, @ckRIFF, 0) = 0 do
  885.      begin
  886.           { quickly check for corrupt RIFF file--don't ascend past end!  }
  887.           if (ck.dwDataOffset + ck.cksize > ckRIFF.dwDataOffset + ckRIFF.ckSize) then
  888.           begin
  889.              if hasFormat and hasData then
  890.                 break
  891.              else if (ck.dwDataOffset + ck.cksize > wio.dwFileSize) then
  892.              begin
  893.                 ck.ckSize := wio.dwFileSize-ck.dwDataOffset;
  894.                 {goto ERROR_READING_WAVE;}
  895.              end;
  896.           end;
  897.           if CheckDataSize then
  898.           begin
  899.              NextOffset := ck.dwDataOffset-8;
  900.              CheckDataSize := False;
  901.           end;
  902.           if ck.ckid = mmioFOURCC('L', 'I', 'S', 'T') then
  903.           begin
  904.        if (ck.fccType = mmioFOURCC('I', 'N', 'F', 'O')) then
  905.                begin
  906.                     TempRes := RiffReadINFO(hmmio, @ck, wio.lpInfo);
  907.                     if TempRes <> 0 then
  908.                     begin
  909.                          Result := TempRes;
  910.                          goto ERROR_READING_WAVE;
  911.     end;
  912.                end;
  913.           end
  914.           else if ck.ckid = mmioFOURCC('D', 'I', 'S', 'P') then
  915.           begin
  916.        TempRes := RiffReadDISP(hmmio, @ck, wio.lpDisp);
  917.                if TempRes <> 0 then
  918.                begin
  919.                   Result := TempRes;
  920.                   goto ERROR_READING_WAVE;
  921.        end;
  922.           end
  923.           else if ck.ckid = mmioFOURCC('f', 'm', 't', ' ') then
  924.           begin
  925.                { !?! another format chunk !?! }
  926.                if (lpwio <> Nil) then break;
  927.                { get size of the format chunk, allocate and lock memory    }
  928.                { for it. we always alloc a complete extended format header }
  929.                { (even for PCM headers that do not have the cbSize field   }
  930.                { defined--we just set it to zero).                         }
  931.                dw := ck.cksize;
  932.                if (dw < sizeof(TWAVEFORMATEX)) then
  933.                    dw := sizeof(TWAVEFORMATEX);
  934.                inc(dw, sizeof(TWAVEIOCB) - sizeof(TWAVEFORMATEX));
  935.                lpwio := GlobalAllocMem(dw);
  936.                if (lpwio = Nil) then
  937.                begin
  938.                     Result := WIOERR_NOMEM;
  939.                     goto ERROR_READING_WAVE;
  940.                end;
  941.                lpwio^.dwSize := dw;
  942.                { read the format chunk }
  943.                Result := WIOERR_FILEERROR;
  944.                dw := ck.cksize;
  945.                if mmioRead(hmmio, PChar(@lpwio^.wfx), dw) <> dw then
  946.                   goto ERROR_READING_WAVE;
  947.                hasFormat := True;
  948.           end
  949.           else if ck.ckid = mmioFOURCC('d', 'a', 't', 'a') then
  950.           begin
  951.                { !?! multiple data chunks !?! }
  952.                if (wio.dwDataBytes <> 0) then break;
  953.                { just hang on to the total length in bytes of this data }
  954.                { chunk..                                                }
  955.                wio.dwDataBytes := ck.cksize;
  956.                { offset of data portion of data chunk }
  957.        wio.dwDataOffset:= ck.dwDataOffset;
  958.                CheckDataSize   := True;
  959.                hasData         := True;
  960.           end
  961.           else if ck.ckid = mmioFOURCC('f', 'a', 'c', 't') then
  962.           begin
  963.                { !?! multiple fact chunks !?! }
  964.                if (wio.dwDataSamples <> $FFFFFFFF) then break;
  965.                { read the first dword in the fact chunk--it's the only    }
  966.                { info we need (and is currently the only info defined for }
  967.                { the fact chunk...)                                       }
  968.                { if this fails, dwDataSamples will remain -1 so we will   }
  969.                { deal with it later...                                    }
  970.                 mmioRead(hmmio, PChar(@wio.dwDataSamples), sizeof(Longint));
  971.           end;
  972.           { step up to prepare for next chunk.. }
  973.           if mmioAscend(hmmio, @ck, 0) <> 0 then
  974.              { bug fix for files with not 4 byte aligned chunks }
  975.              if (wio.dwDataBytes <> 0) then break
  976.              else goto ERROR_READING_WAVE;
  977.      end;
  978.      if (dwFlags and RIFF_INFO_ONLY = 0) then
  979.      begin
  980.         { if no fmt chunk was found, then die! }
  981.         if (lpwio = Nil) then
  982.         begin
  983.            Result := WIOERR_ERROR;
  984.            goto ERROR_READING_WAVE;
  985.         end;
  986.         wio.dwDataBytes := ((NextOffset-wio.dwDataOffset) div lpwio^.wfx.nBlockAlign)*lpwio^.wfx.nBlockAlign;
  987.         
  988.         { some wave files have wrong entrys for AvgBytesPerSecond and }
  989.         { BlockAlign so we calculate them ourself                     }
  990.         if (lpwio^.wfx.wFormatTag = WAVE_FORMAT_PCM) then
  991.         with lpwio^.wfx do
  992.         begin
  993.             nBlockAlign    := (wBitsPerSample * nChannels) div 8;
  994.             nAvgBytesPerSec:= nBlockAlign * nSamplesPerSec;
  995.         end;
  996.         { all wave files other than PCM are _REQUIRED_ to have a fact chunk }
  997.         { telling the number of samples that are contained in the file. it  }
  998.         { is optional for PCM (and if not present, we compute it here).     }
  999.         { check for corrupt fact chunk and repair }
  1000.         if (wio.dwDataSamples <> wioBytesToSamplesEx(lpwio,wio.dwDataBytes)) then
  1001.             wio.dwDataSamples := wioBytesToSamplesEX(lpwio,wio.dwDataBytes);
  1002.         { cool! no problems... }
  1003.         lpwio^.hmmio         := 0;
  1004.         lpwio^.dwFlags       := dwFlags;
  1005.         lpwio^.dwFileSize    := wio.dwFileSize;
  1006.         lpwio^.dwDataBytes   := wio.dwDataBytes;
  1007.         lpwio^.dwDataSamples := wio.dwDataSamples;
  1008.         lpwio^.dwDataOffset  := wio.dwDataOffset;
  1009.         lpwio^.dwFirstSample := 0;
  1010.         lpwio^.dwLastSample  := wio.dwDataSamples;
  1011.         lpwio^.dwBytesLeft   := 0;
  1012.         lpwio^.dwPosition    := 0;
  1013.         lpwio^.lpFilePath    := wio.lpFilePath;
  1014.         lpwio^.lpDisp      := wio.lpDisp;
  1015.         lpwio^.lpInfo      := wio.lpInfo;
  1016.      end
  1017.      else
  1018.      begin
  1019.         dw := sizeof(TWAVEFORMATEX) + sizeof(TWAVEIOCB);
  1020.         lpwio := GlobalAllocMem(dw);
  1021.         if (lpwio = Nil) then
  1022.         begin
  1023.            Result := WIOERR_NOMEM;
  1024.            goto ERROR_READING_WAVE;
  1025.         end;
  1026.         FillChar(lpwio^,dw,0);
  1027.         lpwio^.dwSize     := dw;
  1028.         lpwio^.dwFlags    := dwFlags;
  1029.         lpwio^.lpFilePath := wio.lpFilePath;
  1030.         lpwio^.lpDisp   := wio.lpDisp;
  1031.         lpwio^.lpInfo   := wio.lpInfo;
  1032.      end;
  1033.      wioFileClose(hmmio, hMem);
  1034.      Result := WIOERR_NOERROR;
  1035.      exit;
  1036.      { return error (after minor cleanup) }
  1037. ERROR_READING_WAVE:
  1038.      wioFileClose(hmmio, hMem);
  1039.      wioFreeFileInfo(lpwio);
  1040.      if (lpwio <> Nil) then GlobalFreeMem(Pointer(lpwio));
  1041.      lpwio := Nil;
  1042. end;
  1043. {**************************************************************************}
  1044. function wioCreateFileInfo(Var lpwio: PWAVEIOCB; pwfx: PWaveFormatEx): integer;
  1045. Label ERROR_CREATE_INFO;
  1046. Var
  1047.    dwSize: Longint;
  1048.    TempRes: integer;
  1049.    ExtraAlloc: Longint;
  1050. begin
  1051.      { default our error return (assume the worst) }
  1052.      Result := WIOERR_BADPARAM;
  1053.      lpwio := Nil;
  1054.      if (pwfx = Nil) then
  1055.         goto ERROR_CREATE_INFO;
  1056.      { allocate and lock memory for lpwio. we always alloc a complete }
  1057.      { extended format header (even for PCM headers that do not have  }
  1058.      { the cbSize field defined--we just set it to zero).                         }
  1059.      if (pwfx^.wFormatTag = WAVE_FORMAT_PCM) then
  1060.         ExtraAlloc := 0
  1061.      else
  1062.         ExtraAlloc := pwfx^.cbSize;
  1063.      dwSize := sizeOf(TWAVEIOCB) + ExtraAlloc;
  1064.      lpwio := GlobalAllocMem(dwSize);
  1065.      if (lpwio = Nil) then
  1066.      begin
  1067.         Result := WIOERR_NOMEM;
  1068.         goto ERROR_CREATE_INFO;
  1069.      end;
  1070.      { set the wio struc size }
  1071.      lpwio^.dwSize := dwSize;
  1072.      { copy the WaveFormatEx struc to lpwio's }
  1073.      Move(pwfx^, lpwio^.wfx, sizeOf(TWAVEFORMATEX) + ExtraAlloc);
  1074.      { create a new INFO struc }
  1075.      TempRes := RiffInitINFO(lpwio^.lpInfo);
  1076.      if (TempRes <> 0) then
  1077.      begin
  1078.         Result := TempRes;
  1079.         goto ERROR_CREATE_INFO;
  1080.      end;
  1081.      { create a new DISP list }
  1082.      TempRes := RiffInitDISP(lpwio^.lpDisp);
  1083.      if (TempRes <> 0) then
  1084.      begin
  1085.         Result := TempRes;
  1086.         goto ERROR_CREATE_INFO;
  1087.      end;
  1088.      Result := WIOERR_NOERROR;
  1089.      exit;
  1090.      { return error (after minor cleanup) }
  1091. ERROR_CREATE_INFO:
  1092.      wioFreeFileInfo(lpwio);
  1093. end;
  1094. {**************************************************************************}
  1095. function wioCopyFileInfo(lpwioDst, lpwioSrc: PWAVEIOCB): integer;
  1096. begin
  1097.      { default our error return (assume the worst) }
  1098.      Result := WIOERR_BADPARAM;
  1099.      if (lpwioSrc = Nil) or (lpwioDst = nil) then
  1100.         exit;
  1101.      Result := WIOERR_ERROR;
  1102.      { copy the INFO chunk to the destination }
  1103.      if RiffCopyInfo(lpwioDst^.lpInfo, lpwioSrc^.lpInfo) <> 0 then
  1104.         exit;
  1105.      { copy the DISP chunk to the destination }
  1106.      if RiffCopyDISP(lpwioDst^.lpDisp, lpwioSrc^.lpDisp) <> 0 then
  1107.         exit;
  1108.      Result := WIOERR_NOERROR;
  1109. end;
  1110. {**************************************************************************}
  1111. function wioBuildFileInfoFromMem(Var lpwio: PWaveIOCB; Memory: Pointer; MemSize: DWORD): Word;
  1112. Var
  1113.    mmioInfo: TMMIOINFO;
  1114. begin
  1115.    Result := WIOERR_FILEERROR;
  1116.    lpwio  := nil;
  1117.    if (Memory <> nil) and (MemSize > 0) then
  1118.    begin
  1119.       FillChar(mmioInfo, sizeOf(TMMIOINFO),0);
  1120.       mmioInfo.pchBuffer := Memory;
  1121.       mmioInfo.cchBuffer := MemSize;
  1122.       Result := wioReadFileInfo(lpwio, PChar(@mmioInfo),
  1123.                                 mmioFOURCC('W', 'A', 'V', 'E'), RIFF_MEMORY);
  1124.    end;
  1125. end;
  1126. {**************************************************************************}
  1127. function wioBuildFileInfoFromResource(Var lpwio: PWaveIOCB; ResourceName: PChar): Word;
  1128. begin
  1129.    lpwio  := nil;
  1130.    Result := wioReadFileInfo(lpwio, ResourceName,
  1131.                              mmioFOURCC('W', 'A', 'V', 'E'), RIFF_RESOURCE);
  1132. end;
  1133. {**************************************************************************}
  1134. function  wioBuildFileInfoFromRAWEx(Var lpwio: PWaveIOCB; lpFileName: PChar; DataOffset: DWORD;
  1135.                                     pwfx: PWaveFormatEx): integer;
  1136. var
  1137.    h: THandle;
  1138. begin
  1139.    Result := WIOERR_FILEERROR;
  1140.    lpwio  := nil;
  1141.    if wioCreateFileInfo(lpwio, pwfx) = WIOERR_NOERROR then
  1142.    begin
  1143.       h := FileOpen(StrPas(lpFileName), fmOpenRead or fmShareDenyNone);
  1144.       if (h <> $FFFFFFFF) then
  1145.       with lpwio^ do
  1146.       begin
  1147.          dwFlags      := RAW_FILE;
  1148.          dwFileSize   := FileSeek(h, 0, 2);
  1149.          dwDataBytes  := dwFileSize-DataOffset;
  1150.          dwDataOffset := DataOffset;
  1151.          dwDataSamples:= wioBytesToSamplesEx(lpwio,dwDataBytes);
  1152.          dwFirstSample:= 0;
  1153.          dwLastSample := dwDataSamples;
  1154.          dwBytesLeft  := 0;
  1155.          dwPosition   := 0;
  1156.          lpFilePath   := StrNew(lpFileName);
  1157.          FileClose(h);
  1158.          Result := WIOERR_NOERROR;
  1159.       end
  1160.       else wioFreeFileInfo(lpwio);
  1161.    end;
  1162. end;
  1163. {**************************************************************************}
  1164. function  wioBuildFileInfoFromRAW(Var lpwio: PWaveIOCB; lpFileName: PChar;
  1165.                                   DataOffset, BitLength,
  1166.                                   Channels, SampleRate: DWORD): integer;
  1167. var
  1168.    wfx: TWaveFormatEx;
  1169. begin
  1170.    pcmBuildWaveHeader(@wfx,BitLength,Channels,SampleRate);
  1171.    Result := wioBuildFileInfoFromRAWEx(lpwio,lpFileName,DataOffset,@wfx);
  1172. end;
  1173. {**************************************************************************}
  1174. function wioWriteFileInfo(Var lpwio: PWAVEIOCB; lpFilePath: PChar): integer;
  1175. Label ERROR_CANNOT_WRITE;
  1176. Var
  1177.    hmmio: THMMIO;
  1178.    ckDATA, ckRIFF: TMMCKINFO;
  1179.    dw: Longint;
  1180. begin
  1181.     { default our error return (assume the worst) }
  1182.     Result := WIOERR_FILEERROR;
  1183.     hmmio := 0;
  1184.     { validate a couple of things }
  1185.     if (lpwio = Nil) or (lpFilePath = Nil) then
  1186.     begin
  1187.        Result := WIOERR_BADPARAM;
  1188.        goto ERROR_CANNOT_WRITE;
  1189.     end;
  1190.     { yes, this is the open... }
  1191.     hmmio := mmioOpen(lpFilePath, Nil, MMIO_CREATE or MMIO_READWRITE or MMIO_ALLOCBUF);
  1192.     if (hmmio = 0) then
  1193.        goto ERROR_CANNOT_WRITE;
  1194.     { create the RIFF chunk of form type 'WAVE' }
  1195.     ckRIFF.fccType := mmioFOURCC('W', 'A', 'V', 'E');
  1196.     ckRIFF.cksize  := 0;
  1197.     if mmioCreateChunk(hmmio, @ckRIFF, MMIO_CREATERIFF) <> 0 then
  1198.        goto ERROR_CANNOT_WRITE;
  1199.     { now create the destination fmt and data chunks _in that order_       }
  1200.     { hmmio is now descended into the 'RIFF' chunk--create the format chunk}
  1201.     { and write the format header into it                                  }
  1202.     dw := wioSizeOfWaveFormat(@lpwio^.wfx);
  1203.     ckDATA.ckid := mmioFOURCC('f', 'm', 't', ' ');
  1204.     ckDATA.cksize := dw;
  1205.     if mmioCreateChunk(hmmio, @ckDATA, 0) <> 0 then
  1206.        goto ERROR_CANNOT_WRITE;
  1207.     { Write the WAVEFORMAT structure to the 'fmt ' chunk. }
  1208.     if mmioWrite(hmmio, @lpwio^.wfx, dw) <> dw then
  1209.        goto ERROR_CANNOT_WRITE;
  1210.     { Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk. }
  1211.     if mmioAscend(hmmio, @ckDATA, 0) <> 0 then
  1212.        goto ERROR_CANNOT_WRITE;
  1213.     { create the data chunk AND STAY DESCENDED... for reasons that }
  1214.     { will become apparent later..                                 }
  1215.     ckDATA.ckid   := mmioFOURCC('d', 'a', 't', 'a');
  1216.     ckDATA.cksize := 0;
  1217.     ckData.dwFlags:= MMIO_DIRTY;
  1218.     if mmioCreateChunk(hmmio, @ckDATA, 0) <> 0 then
  1219.        goto ERROR_CANNOT_WRITE;
  1220.     { to close the file do:
  1221.     mmioAscend(hmmio, @ckData, 0);
  1222.     mmioAscend(hmmio, @ckRIFF, 0);
  1223.     mmioClose(hmmio, 0); }
  1224.     { cool! no problems.. }
  1225.     lpwio^.hmmio         := hmmio;
  1226.     lpwio^.ckRIFF        := ckRIFF;
  1227.     lpwio^.ckDATA        := ckDATA;
  1228.     lpwio^.dwDataOffset  := ckDATA.dwDataOffset;
  1229.     lpwio^.lpFilePath    := StrNew(lpFilePath);
  1230.     lpwio^.dwDataSamples := wioBytesToSamplesEx(lpwio, lpwio^.dwDataBytes);
  1231.     lpwio^.dwFirstSample := 0;
  1232.     lpwio^.dwLastSample  := lpwio^.dwDataSamples;
  1233.     Result := WIOERR_NOERROR;
  1234.     exit;
  1235.     { return error (after minor cleanup) }
  1236. ERROR_CANNOT_WRITE:
  1237.     if (hmmio <> 0) then
  1238.        mmioClose(hmmio, 0);    { close the new file }
  1239.     { delete the half-written file. }
  1240.     wioFileDelete(lpFilePath);
  1241. end;
  1242. {**************************************************************************}
  1243. function wioFreeFileInfo(Var lpwio: PWAVEIOCB): integer;
  1244. begin
  1245.      { validate a couple of things... }
  1246.      if (lpwio = Nil) then
  1247.      begin
  1248.   Result := WIOERR_BADPARAM;
  1249.           exit;
  1250.      end;
  1251.      { get rid of stuff... }
  1252.      if (lpwio^.hmmio <> 0) then
  1253.      begin
  1254.           if (lpwio^.dwFlags and RAW_FILE <> 0) then
  1255.               FileClose(lpwio^.hmmio)
  1256.           else
  1257.               mmioClose(lpwio^.hmmio, 0);
  1258.   lpwio^.hmmio := 0;
  1259.      end;
  1260.      if (lpwio^.lpFilePath <> Nil) then
  1261.         StrDispose(lpwio^.lpFilePath);
  1262.      if (lpwio^.lpInfo <> Nil) then
  1263. RiffFreeINFO(lpwio^.lpInfo);
  1264.      if (lpwio^.lpDisp <> Nil) then
  1265. RiffFreeDISP(lpwio^.lpDisp,True);
  1266.      GlobalFreeMem(Pointer(lpwio));
  1267.      lpwio := Nil;
  1268.      Result := WIOERR_NOERROR;
  1269. end;
  1270. (**************************************************************************
  1271.  * This routine will copy from a source wave file to a destination wave
  1272.  * file all those useless chunks (well, the ones useless to conversions,
  1273.  * etc --> apparently people use them!). The source will be seeked to the
  1274.  * begining, but the destination has to be at a current pointer to put the
  1275.  * new chunks. This will also seek back to the start of the wave riff
  1276.  * header at the end of the routine.
  1277.  *
  1278.  * Both files must be open !!!
  1279.  *
  1280.  * Returns 0 if successful, else the error code. If this routine fails, it
  1281.  * still attemps to seek back to the start of the wave riff header, though
  1282.  * this too could be unsuccessful.
  1283.  **************************************************************************)
  1284. function wioWaveCopyUselessChunks(lpwioSrc, lpwioDst: PWaveIOCB): integer;
  1285. Label COPY_ERROR;
  1286. begin
  1287.      Result := WIOERR_FILEERROR;
  1288.      { First seek to the start of the file, not including the riff header }
  1289.      with lpwioSrc^ do
  1290.      begin
  1291.         if mmioSeek(hmmio, ckRIFF.dwDataOffset + sizeOf(FOURCC), SEEK_SET) = -1 then
  1292.            goto COPY_ERROR;
  1293.         while mmioDescend(hmmio, @ckDATA, @ckRIFF, 0) = 0 do
  1294.         begin
  1295.            { quickly check for corrupt RIFF file--don't ascend past end! }
  1296.            if (ckData.dwDataOffset + ckDATA.cksize > ckRIFF.dwDataOffset + ckRIFF.cksize) then
  1297.               goto COPY_ERROR;
  1298.            { copy chunks that are OK to copy }
  1299.            if ckDATA.ckid = mmioFOURCC('c', 'u', 'e', ' ') then
  1300.               { it doesn't make much sense }
  1301.               RiffCopyChunk(hmmio, lpwioDst^.hmmio, @ckDATA)
  1302.            else if ckDATA.ckid = mmioFOURCC('p', 'l', 's', 't') then
  1303.               { although without the 'cue' chunk, it doesn't make much sense }
  1304.               RiffCopyChunk(hmmio, lpwioDst^.hmmio, @ckDATA)
  1305.            { don't copy unknown chunks }
  1306.            else break;
  1307.            { step up to prepare for next chunk.. }
  1308.            mmioAscend(hmmio, @ckDATA, 0);
  1309.         end;
  1310.      end;
  1311.      Result := WIOERR_NOERROR;
  1312. COPY_ERROR:
  1313.      { Seek back to source RIFF header }
  1314.      with lpwioSrc^ do
  1315.      mmioSeek(hmmio, ckRIFF.dwDataOffset + sizeof(FOURCC), SEEK_SET);
  1316. end;
  1317. {**************************************************************************}
  1318. (* TODO: does not work !? mmioGetInfo returns in cchBuffer bad size !!!???*)
  1319. function wioSetIOBufferSize(lpwio: PWaveIOCB; dwSize: integer): integer;
  1320. begin
  1321.      Result := WIOERR_BADPARAM;
  1322.      { validate a couple of things... }
  1323.      if (lpwio = Nil) then exit;
  1324.      Result := WIOERR_ERROR;
  1325.      if (lpwio^.dwFlags and RIFF_MEMORY <> 0) or
  1326.         (lpwio^.dwFlags and RIFF_RESOURCE <> 0) or
  1327.         (lpwio^.dwFlags and RAW_FILE <> 0) then
  1328.         Result := WIOERR_NOERROR
  1329.      else if (lpwio^.hmmio <> 0) and (dwSize >= 0) then
  1330.         Result := mmioSetBuffer(lpwio^.hmmio, Nil, dwSize, 0);
  1331. end;
  1332. {**************************************************************************}
  1333. function wioWaveOpen(lpwio: PWaveIOCB): integer;
  1334. begin
  1335.      Result := WIOERR_BADPARAM;
  1336.      { validate a couple of things... }
  1337.      if (lpwio = Nil) then exit;
  1338.      Result := WIOERR_FILEERROR;
  1339.      { (re)open the file }
  1340.      if (lpwio^.hmmio = 0) then
  1341.      with lpwio^ do
  1342.      begin
  1343.         if (dwFlags and RAW_FILE <> 0) then
  1344.             hmmio := FileOpen(StrPas(lpFilePath),fmOpenRead or fmShareDenyNone)
  1345.         else wioFileOpen(hmmio, ckRIFF, hMem, lpFilePath,
  1346.                          mmioFOURCC('W', 'A', 'V', 'E'),dwFlags);
  1347.      end;
  1348.      { set start position }
  1349.      if (lpwio^.hmmio <> 0) then
  1350.         if wioWaveSetPosition(lpwio, lpwio^.dwPosition) = 0 then
  1351.            Result := WIOERR_NOERROR;
  1352. end;
  1353. {**************************************************************************}
  1354. function wioWaveClose(lpwio: PWaveIOCB): integer;
  1355. Label ERROR_CANNOT_WRITE;
  1356. Var
  1357.    mmioInfo: TMMIOINFO;
  1358. begin
  1359.      Result := WIOERR_NOERROR;
  1360.      if (lpwio = Nil) or (lpwio^.hmmio = 0) then exit;
  1361.      with lpwio^ do
  1362.      begin
  1363.         Result := WIOERR_FILEERROR;
  1364.         if (dwFlags and RAW_FILE = 0) and
  1365.            (ckData.dwFlags and MMIO_DIRTY <> 0) then
  1366.         begin
  1367.            if mmioGetInfo(hmmio, @mmioInfo, 0) <> 0 then
  1368.               goto ERROR_CANNOT_WRITE;
  1369.            if mmioFlush(hmmio,0) <> 0 then
  1370.               goto ERROR_CANNOT_WRITE;    { cannot write file, probably }
  1371.            if mmioInfo.dwFlags and MMIO_CREATE = 0 then
  1372.            begin
  1373.               { rewrite the size of data chunk }
  1374.               ckData.cksize := 0;
  1375.               ckData.dwFlags:= ckData.dwFlags or MMIO_DIRTY;
  1376.               { seek to the end of the chunk first }
  1377.               if mmioSeek(hmmio,dwDataOffset+dwDataBytes,SEEK_SET) = -1 then
  1378.                  goto ERROR_CANNOT_WRITE;    { cannot seek, probably }
  1379.               { force the rif chunk to rewrite }
  1380.               ckRiff.cksize := 0;
  1381.               ckRiff.dwFlags:= ckRiff.dwFlags or MMIO_DIRTY;
  1382.            end;
  1383.            { Ascend the output file out of the 'data' chunk - this will }
  1384.            { cause the chunk size of the 'data' chunk to be written.    }
  1385.            if mmioAscend(hmmio, @ckDATA, 0) <> 0 then
  1386.               goto ERROR_CANNOT_WRITE;    { cannot write file, probably }
  1387.            { Now create the fact chunk, not required for PCM but nice to have. }
  1388.            ckDATA.ckid   := mmioFOURCC('f', 'a', 'c', 't');
  1389.            ckDATA.cksize := 0;
  1390.            if mmioCreateChunk(hmmio, @ckDATA, 0) <> 0 then
  1391.               goto ERROR_CANNOT_WRITE;
  1392.            { If it didn't fail, write the fact chunk out }
  1393.            if mmioWrite(hmmio, @dwDataSamples, sizeOf(Longint)) <> sizeOf(Longint) then
  1394.               goto ERROR_CANNOT_WRITE;
  1395.            { Now ascend out of the fact chunk... }
  1396.            if mmioAscend(hmmio, @ckDATA, 0) <> 0 then
  1397.               goto ERROR_CANNOT_WRITE;
  1398.            { now write out possibly editted chunks... }
  1399.            if RiffWriteDISP(hmmio, lpDisp) <> 0 then
  1400.               goto ERROR_CANNOT_WRITE;
  1401.            if RiffWriteINFO(hmmio, lpInfo) <> 0 then
  1402.               goto ERROR_CANNOT_WRITE;
  1403.            { Ascend the output file out of the 'RIFF' chunk - this will }
  1404.            { cause the chunk size of the 'RIFF' chunk to be written.    }
  1405.            if mmioAscend(hmmio, @ckRIFF, 0) <> 0 then
  1406.               goto ERROR_CANNOT_WRITE;    { cannot write file, probably }
  1407.            { Get the file size }
  1408.            dwFileSize := mmioSeek(hmmio, 0, SEEK_END);
  1409.            if (dwFileSize = $FFFFFFFF) then
  1410.                goto ERROR_CANNOT_WRITE;
  1411.            { cool! no problems.. }
  1412.            dwLastSample := dwDataSamples;
  1413.         end;
  1414.         Result := WIOERR_NOERROR;
  1415. ERROR_CANNOT_WRITE:
  1416.         { finally close the file }
  1417.         if (dwFlags and RAW_FILE <> 0) then
  1418.         begin
  1419.            FileClose(hmmio);
  1420.            hmmio := 0;
  1421.         end
  1422.         else
  1423.             wioFileClose(hmmio, hMem);
  1424.         dwBytesLeft := 0;
  1425.         dwPosition := 0;
  1426.      end;
  1427. end;
  1428. (**************************************************************************
  1429.  * This routine loads a full wave file into memory. Be careful, wave files
  1430.  * can get pretty big these days :).
  1431.  *
  1432.  *       lpFilePath  -   Filename
  1433.  *       Size        -   Size of loaded wave (returned)
  1434.  *       pwfx        -   Pointer to waveFormatEx structure.  The wfx
  1435.  *                       structure IS ALLOCATED by this routine!  Make
  1436.  *                       sure to free it!
  1437.  *       Buffer      -   Pointer to a byte pointer (globalalloc) which is
  1438.  *                       allocated by this routine. Make sure to free it!
  1439.  *
  1440.  *       Returns 0 if successful, else the error code.
  1441.  **************************************************************************)
  1442. function wioWaveLoadFile(lpFilePath: PChar;           { (IN)  }
  1443.                          Var pwfx: PWaveFormatEx;     { (OUT) }
  1444.                          Var Buffer: PChar;           { (OUT) }
  1445.                          Var Size: DWORD): integer;   { (OUT) }
  1446. Label ERROR_LOADING, DONE_LOADING;
  1447. Var
  1448.    lpwio: PWaveIOCB;
  1449.    Res: Longint;
  1450. begin
  1451.      pwfx := Nil;
  1452.      Buffer := Nil;
  1453.      lpwio := Nil;
  1454.      Size := 0;
  1455.      Result := wioReadFileInfo(lpwio, lpFilePath, mmioFOURCC('W', 'A', 'V', 'E'), RIFF_FILE);
  1456.      if (Result <> 0) then
  1457.         goto ERROR_LOADING;
  1458.      Result := wioWaveOpen(lpwio);
  1459.      if (Result <> 0) then
  1460.         goto ERROR_LOADING;
  1461.      { Ok, size of wave data is in lpwio^.dwDataSize, allocate that buffer. }
  1462.      Buffer := GlobalAllocPtr(GMEM_FIXED, lpwio^.dwDataBytes);
  1463.      if (Buffer = Nil) then
  1464.      begin
  1465.         Result := WIOERR_NOMEM;
  1466.         goto ERROR_LOADING;
  1467.      end;
  1468.      Res := wioWaveReadData(lpwio, Buffer, lpwio^.dwDataBytes);
  1469.      if (Res <= 0) then
  1470.      begin
  1471.         Result := WIOERR_FILEERROR;
  1472.         goto ERROR_LOADING;
  1473.      end;
  1474.      pwfx := GlobalAllocPtr(GMEM_FIXED, sizeOf(TWaveFormatEx) + lpwio^.wfx.cbSize);
  1475.      if (pwfx = Nil) then
  1476.      begin
  1477.         Result := WIOERR_NOMEM;
  1478.         goto ERROR_LOADING;
  1479.      end;
  1480.      move(lpwio^.wfx, pwfx^, sizeOf(TWaveFormatEx) + lpwio^.wfx.cbSize);
  1481.      Size := lpwio^.dwDataBytes;
  1482.      Result := WIOERR_NOERROR;
  1483.      goto DONE_LOADING;
  1484. ERROR_LOADING:
  1485.      if (Buffer <> Nil) then
  1486.      begin
  1487.         GlobalFreePtr(Buffer);
  1488.         Buffer := Nil;
  1489.      end;
  1490.      if (pwfx <> Nil) then
  1491.      begin
  1492.         GlobalFreePtr(pwfx);
  1493.         pwfx := Nil;
  1494.      end;
  1495. DONE_LOADING:
  1496.      { Close the wave file. }
  1497.      wioWaveClose(lpwio);
  1498.      wioFreeFileInfo(lpwio);
  1499. end;
  1500. (**************************************************************************
  1501.  * This routine saves a wave file currently in memory.
  1502.  * lpFilePath -   FileName to save to.  Automatically overwritten, be careful!
  1503.  * Size       -   Size in bytes to write.
  1504.  * pwfx       -   Pointer to waveformatex structure.
  1505.  * Buffer     -   Pointer to the data.
  1506.  **************************************************************************)
  1507. function wioWaveSaveFile(lpFilePath: PChar;                  { (IN) }
  1508.                          pwfx: PWAVEFORMATEX;                { (IN) }
  1509.                          Buffer: PChar;                      { (IN) }
  1510.                          Size: DWORD): integer;              { (IN) }
  1511. Label ERROR_SAVING;
  1512. Var
  1513.    lpwio: PWaveIOCB;
  1514. begin
  1515.      Result := wioCreateFileInfo(lpwio, pwfx);
  1516.      if (Result <> 0) then
  1517.         goto ERROR_SAVING;
  1518.      Result := wioWriteFileInfo(lpwio, lpFilePath);
  1519.      if (Result <> 0) then
  1520.         goto ERROR_SAVING;
  1521.      Result := wioWaveWriteData(lpwio, Buffer, Size);
  1522.      if (Result <= 0) then
  1523.      begin
  1524.         Result := WIOERR_FILEERROR;
  1525.         goto ERROR_SAVING;
  1526.      end;
  1527.      Result := WIOERR_NOERROR;
  1528. ERROR_SAVING:
  1529.      { Close the wave file. }
  1530.      wioWaveClose(lpwio);
  1531.      wioFreeFileInfo(lpwio);
  1532.      if Result <> WIOERR_NOERROR then
  1533.         { delete the half-written file. }
  1534.         wioFileDelete(lpFilePath);
  1535. end;
  1536. {**************************************************************************}
  1537. function wioWaveSetFirstSample(lpwio: PWaveIOCB; dwSample: DWORD): integer;
  1538. begin
  1539.      Result := WIOERR_BADPARAM;
  1540.      if (lpwio <> Nil) then
  1541.      begin
  1542.         with lpwio^do
  1543.         begin
  1544.            if (Longint(dwSample) >= 0) and (dwSample < dwLastSample) then
  1545.            begin
  1546.               dwFirstSample := dwSample;
  1547.               dwBytesLeft := wioSamplesToBytesEx(lpwio, dwLastSample-dwFirstSample);
  1548.               Result := WIOERR_NOERROR;
  1549.            end;
  1550.         end;
  1551.      end;
  1552. end;
  1553. {**************************************************************************}
  1554. function wioWaveSetLastSample(lpwio: PWaveIOCB; dwSample: DWORD): integer;
  1555. begin
  1556.      Result := WIOERR_BADPARAM;
  1557.      if (lpwio <> Nil) then
  1558.      begin
  1559.         with lpwio^do
  1560.         begin
  1561.            if (dwSample > dwFirstSample) and (dwSample <= dwDataSamples) then
  1562.            begin
  1563.               dwLastSample := dwSample;
  1564.               { set the bytes to play }
  1565.               dwBytesLeft := wioSamplesToBytesEx(lpwio, dwLastSample-dwFirstSample);
  1566.               Result := WIOERR_NOERROR;
  1567.            end;
  1568.         end;
  1569.      end;
  1570. end;
  1571. {**************************************************************************}
  1572. function wioWaveSetPosition(lpwio: PWaveIOCB; dwSample: DWORD): integer;
  1573. Var
  1574.    dwDataPos: DWORD;
  1575. begin
  1576.      Result := WIOERR_FILEERROR;
  1577.      if (lpwio <> Nil) and (Longint(dwSample) >= 0) then
  1578.      with lpwio^ do
  1579.      begin
  1580.         { make sure we are in range }
  1581.         {$IFDEF BUILD_ACTIVEX}
  1582.         dwSample := MinMax(dwSample, 0, dwLastSample-dwFirstSample);
  1583.         {$ELSE}
  1584.         dwSample := MinMax(dwSample, 0, dwLastSample-dwFirstSample-1);
  1585.         {$ENDIF}
  1586.         if (hmmio <> 0) then
  1587.         begin
  1588.            if (dwFlags and RAW_FILE <> 0) then
  1589.            begin
  1590.               { convert samples to bytes }
  1591.               dwDataPos := Min(wioSamplesToBytesEx(lpwio,dwFirstSample+dwSample),dwDataBytes);
  1592.               { align to nBlockAlign }
  1593.               dwDataPos := (dwDataPos div wfx.nBlockAlign)*wfx.nBlockAlign;
  1594.               { set the position }
  1595.               if FileSeek(hmmio, dwDataOffset+dwDataPos, 0) <> -1 then
  1596.               begin
  1597.                  { set the bytes to play }
  1598.                  dwBytesLeft := wioSamplesToBytesEx(lpwio, dwLastSample) - dwDataPos;
  1599.                  { set the current file position }
  1600.                  dwPosition := wioBytesToSamplesEx(lpwio, dwDataPos) - dwFirstSample;
  1601.                  Result := WIOERR_NOERROR;
  1602.               end;
  1603.            end
  1604.            else
  1605.            begin
  1606.               dwDataPos := dwDataOffset - 2*sizeof(FOURCC);
  1607.               { go to the 'data' chunk }
  1608.               if mmioSeek(hmmio, dwDataPos, SEEK_SET) = Longint(dwDataPos) then
  1609.               begin
  1610.                  { now we are at start of 'data' chunk, descend into the chunk }
  1611.                  if mmioDescend(hmmio, @ckDATA, Nil, 0) = 0 then
  1612.                  begin
  1613.                     { convert samples to bytes }
  1614.                     dwDataPos := Min(wioSamplesToBytesEx(lpwio,dwFirstSample+dwSample),dwDataBytes);
  1615.                     { align to nBlockAlign }
  1616.                     dwDataPos := (dwDataPos div wfx.nBlockAlign)*wfx.nBlockAlign;
  1617.                     { set the position }
  1618.                     if mmioSeek(hmmio, dwDataPos, SEEK_CUR) <> -1 then
  1619.                     begin
  1620.                        { set the bytes to play }
  1621.                        dwBytesLeft := wioSamplesToBytesEx(lpwio, dwLastSample) - dwDataPos;
  1622.                        { set the current file position }
  1623.                        dwPosition := wioBytesToSamplesEx(lpwio, dwDataPos) - dwFirstSample;
  1624.                        Result := WIOERR_NOERROR;
  1625.                     end;
  1626.                  end;
  1627.               end;
  1628.            end;
  1629.         end
  1630.         else
  1631.         begin
  1632.            { only set the start position (round to blockalign) }
  1633.            dwDataPos := wioSamplesToBytesEx(lpwio, dwFirstSample+dwSample);
  1634.            dwPosition := wioBytesToSamplesEx(lpwio,dwDataPos)-dwFirstSample;
  1635.            Result := WIOERR_NOERROR;
  1636.         end;
  1637.      end;
  1638. end;
  1639. {**************************************************************************}
  1640. function wioWaveReadData(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  1641. Label Again;
  1642. begin
  1643.      Result := $FFFFFFFF;
  1644.      if (lpwio <> Nil) AND (lpwio^.hmmio <> 0) then
  1645.      begin
  1646.         with lpwio^ do
  1647.         begin
  1648.            if (dwBytesLeft > 0) then
  1649.            begin
  1650.               { read the data from the file... }
  1651.               if (dwFlags and RAW_FILE <> 0) then
  1652.                   Result := FileRead(hmmio, Buffer^, Min(nBytes,dwBytesLeft))
  1653.               else
  1654.                   Result := mmioRead(hmmio, Buffer, Min(nBytes,dwBytesLeft));
  1655.               if (Result < nBytes) then dwBytesLeft := 0;
  1656.            end;
  1657.            if (Result > 0) then
  1658.            begin
  1659.               dwBytesLeft := Max(dwBytesLeft-Result,0);
  1660.               dwPosition  := (dwLastSample-dwFirstSample) - wioBytesToSamplesEx(lpwio, dwBytesLeft);
  1661.               { inc(dwPosition,wioBytesToSamples(@wfx, Result));}
  1662.            end;
  1663.         end;
  1664.      end;
  1665. end;
  1666. {**************************************************************************}
  1667. function wioWaveReadDataDirect(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  1668. Label ERROR_CANNOT_READ;
  1669. Var
  1670.    i: Cardinal;
  1671.    CopyLength: DWORD;
  1672.    mmioInfo: TMMIOINFO;
  1673. begin
  1674.      if (lpwio = Nil) or (lpwio^.hmmio = 0) then
  1675.         goto ERROR_CANNOT_READ;
  1676.      with lpwio^ do
  1677.      begin
  1678.         if (dwFlags and RAW_FILE <> 0) then
  1679.             goto ERROR_CANNOT_READ;
  1680.         { read the data from the file... }
  1681.         Result := mmioGetInfo(hmmio, @mmioInfo, 0);
  1682.         if (Result <> 0) then
  1683.            goto ERROR_CANNOT_READ;
  1684.         nBytes := Min(dwBytesLeft, nBytes);
  1685.         i := 0;
  1686.         while i < nBytes do
  1687.         begin
  1688.            { Copy the bytes from the io to the buffer. }
  1689.            if (mmioInfo.pchNext = mmioInfo.pchEndRead) then
  1690.            begin
  1691.               if mmioAdvance(hmmio, @mmioInfo, MMIO_READ) <> 0 then
  1692.                  goto ERROR_CANNOT_READ;
  1693.               if (mmioInfo.pchNext = mmioInfo.pchEndRead) then
  1694.                  goto ERROR_CANNOT_READ;
  1695.            end;
  1696.            { Actual copy. }
  1697.            CopyLength := (mmioInfo.pchEndRead - mmioInfo.pchNext);
  1698.            if (nBytes - i < CopyLength) then
  1699.               CopyLength := nBytes - i;
  1700.            move(PByte(mmioInfo.pchNext)^, PByte(Buffer+i)^, CopyLength);
  1701.            inc(i, CopyLength);
  1702.            inc(mmioInfo.pchNext, CopyLength);
  1703.         end;
  1704.         Result := mmioSetInfo(hmmio, @mmioInfo, 0);
  1705.         if (Result <> 0) then
  1706.            goto ERROR_CANNOT_READ;
  1707.         dec(dwBytesLeft, nBytes);
  1708.         inc(dwPosition, wioBytesToSamplesEx(lpwio, nBytes));
  1709.         Result := nBytes;
  1710.         exit;
  1711.      end;
  1712. ERROR_CANNOT_READ:
  1713.      Result := $FFFFFFFF;
  1714. end;
  1715. {**************************************************************************}
  1716. function wioWaveReadSamples(lpwio: PWaveIOCB; Buffer: PChar; nSamples: DWORD): DWORD;
  1717. Var
  1718.    nBytes: Longint;
  1719. begin
  1720.      Result := $FFFFFFFF;
  1721.      if (lpwio <> Nil) And (nSamples > 0) then
  1722.      begin
  1723.           { convert samples to bytes }
  1724.           nBytes := wioSamplesToBytesEx(lpwio, nSamples);
  1725.           { read the data from the file... }
  1726.           nBytes := wioWaveReadData(lpwio,Buffer,nBytes);
  1727.           if (nBytes > 0) then
  1728.              Result := wioBytesToSamplesEx(lpwio, nBytes);
  1729.      end;
  1730. end;
  1731. {**************************************************************************}
  1732. function wioWaveWriteData(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  1733. var
  1734.    dwPos: DWORD;
  1735. begin
  1736.      Result := $FFFFFFFF;
  1737.      if (lpwio <> Nil) and (lpwio^.hmmio <> 0) and (nBytes > 0) then
  1738.      begin
  1739.         with lpwio^ do
  1740.         begin
  1741.            if (dwFlags and RAW_FILE <> 0) then exit;
  1742.            { write the data to the file... }
  1743.            Result := mmioWrite(hmmio, Buffer, nBytes);
  1744.            if (Result > 0) then
  1745.            begin
  1746.               ckData.dwFlags:= ckData.dwFlags or MMIO_DIRTY;
  1747.               dwPos := DWORD(mmioSeek(hmmio,0,SEEK_CUR))-dwDataOffset;
  1748.               dwPosition := wioBytesToSamplesEx(lpwio, dwPos);
  1749.               if (dwPos > dwDataBytes) then dwDataBytes := dwPos;
  1750.               if (dwPosition > dwDataSamples) then
  1751.               begin
  1752.                  dwDataSamples := dwPosition;
  1753.                  dwLastSample  := dwDataSamples;
  1754.               end;
  1755.               dwBytesLeft := wioSamplesToBytesEx(lpwio, dwLastSample-dwPosition);
  1756.            end
  1757.            else
  1758.            begin
  1759.               { What to do here?  Well, for now, nothing, just return that }
  1760.               { error. maybe delete the file later? }
  1761.            end;
  1762.         end;
  1763.      end;
  1764. end;
  1765. {**************************************************************************}
  1766. function wioWaveWriteDataDirect(lpwio: PWaveIOCB; Buffer: PChar; nBytes: DWORD): DWORD;
  1767. Label ERROR_CANNOT_WRITE;
  1768. Var
  1769.    i: Cardinal;
  1770.    mmioInfo: TMMIOINFO;
  1771.    dwPos: DWORD;
  1772. begin
  1773.      if (lpwio = Nil) or (lpwio^.hmmio = 0) then
  1774.         goto ERROR_CANNOT_WRITE;
  1775.      with lpwio^ do
  1776.      begin
  1777.         if (dwFlags and RAW_FILE <> 0) then
  1778.             goto ERROR_CANNOT_WRITE;
  1779.         Result := mmioGetInfo(hmmio, @mmioInfo, 0);
  1780.         if (Result <> 0) then
  1781.            goto ERROR_CANNOT_WRITE;
  1782.         i := 0;
  1783.         while i < nBytes do
  1784.         begin
  1785.            if (mmioInfo.pchNext = mmioInfo.pchEndWrite) then
  1786.            begin
  1787.               mmioInfo.dwFlags := mmioInfo.dwFlags or MMIO_DIRTY;
  1788.               if mmioAdvance(hmmio, @mmioInfo, MMIO_WRITE) <> 0 then
  1789.                  goto ERROR_CANNOT_WRITE;
  1790.            end;
  1791.            PByte(mmioInfo.pchNext)^ := PByte(Buffer+i)^;
  1792.            inc(mmioInfo.pchNext);
  1793.            inc(Result);
  1794.            inc(i);
  1795.         end;
  1796.         mmioInfo.dwFlags := mmioInfo.dwFlags or MMIO_DIRTY;
  1797.         if mmioSetInfo(hmmio, @mmioInfo, 0) <> 0 then
  1798.            goto ERROR_CANNOT_WRITE;           { cannot flush, probably... }
  1799.         ckData.dwFlags := ckData.dwFlags or MMIO_DIRTY;
  1800.         dwPos := DWORD(mmioSeek(hmmio,0,SEEK_CUR))-dwDataOffset;
  1801.         dwPosition := wioBytesToSamplesEx(lpwio, dwPos);
  1802.         if (dwPos > dwDataBytes) then dwDataBytes := dwPos;
  1803.         if (dwPosition > dwDataSamples) then
  1804.         begin
  1805.            dwDataSamples := dwPosition;
  1806.            dwLastSample  := dwDataSamples;
  1807.         end;
  1808.      end;
  1809.      exit;
  1810. ERROR_CANNOT_WRITE:
  1811.      { What to do here?  Well, for now, nothing, just return that error. }
  1812.      { (maybe delete the file later?                                     }
  1813.      Result := $FFFFFFFF;
  1814. end;
  1815. {**************************************************************************}
  1816. function wioWaveWriteSamples(lpwio: PWaveIOCB; Buffer: PChar; nSamples: DWORD): DWORD;
  1817. Var
  1818.    nBytes: Longint;
  1819. begin
  1820.      Result := $FFFFFFFF;
  1821.      if (lpwio <> Nil) And (nSamples > 0) then
  1822.      begin
  1823.           { convert samples to bytes }
  1824.           nBytes := wioSamplesToBytesEx(lpwio, nSamples);
  1825.           { write the data to the file... }
  1826.           nBytes := wioWaveWriteData(lpwio, Buffer, nBytes);
  1827.           Result := wioBytesToSamplesEx(lpwio, nBytes);
  1828.      end;
  1829. end;
  1830. end.