Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1400 lines
54 KiB

  1. /*
  2. ** Copyright (c) 1985-1994 Microsoft Corporation
  3. **
  4. ** Title: mwrec.c - Multimedia Systems Media Control Interface
  5. ** waveform digital audio driver for RIFF wave files.
  6. ** Routines for recording wave files
  7. */
  8. /*
  9. ** Change log:
  10. **
  11. ** DATE REV DESCRIPTION
  12. ** ----------- ----- ------------------------------------------
  13. ** 18-APR-1990 ROBWI Original
  14. ** 19-JUN-1990 ROBWI Added wave in
  15. ** 13-Jan-1992 MikeTri Ported to NT
  16. ** Aug-1994 Lauriegr This is all out of date
  17. */
  18. /*******************************************************************************
  19. ** !!READ THIS!! *
  20. ** !!READ THIS!! *
  21. ** !!READ THIS!! *
  22. ** *
  23. ** As far as I can make out, this code was never finished.
  24. ** The scheme (which I tried to start writing up in MCIWAVE.H) is that there are
  25. ** a series of NODEs which describe a wave file. As long as there is in fact
  26. ** only one NODE for the file (which is probably the only common case) then this
  27. ** all works fine. If there are multiple NODEs (which you arrive at by inserting
  28. ** bits or deleting bits from the middle) then it all falls apart.
  29. **
  30. ** We're pretty sure nobody's ever used this stuff as it's been broken for years
  31. ** in 16 and 32 bit. We've discovered it just as Daytona is about to ship (that's
  32. ** Windows/NT version 3.5). Maybe NMM wil replace it all anyway.
  33. **
  34. ** This is a half-patched up version with several questions left outstanding.
  35. */
  36. #define UNICODE
  37. #define NOGDICAPMASKS
  38. #define NOVIRTUALKEYCODES
  39. #define NOWINSTYLES
  40. #define NOSYSMETRICS
  41. #define NOMENUS
  42. #define NOICONS
  43. #define NOKEYSTATES
  44. #define NOSYSCOMMANDS
  45. #define NORASTEROPS
  46. #define NOSHOWWINDOW
  47. #define OEMRESOURCE
  48. #define NOATOM
  49. #define NOCLIPBOARD
  50. #define NOCOLOR
  51. #define NOCTLMGR
  52. #define NODRAWTEXT
  53. #define NOGDI
  54. #define NOKERNEL
  55. #define NONLS
  56. #define NOMB
  57. #define NOMEMMGR
  58. #define NOMETAFILE
  59. #define NOOPENFILE
  60. #define NOSCROLL
  61. #define NOTEXTMETRIC
  62. #define NOWH
  63. #define NOWINOFFSETS
  64. #define NOCOMM
  65. #define NOKANJI
  66. #define NOHELP
  67. #define NOPROFILER
  68. #define NODEFERWINDOWPOS
  69. #include <windows.h>
  70. #include "mciwave.h"
  71. #include <mmddk.h>
  72. #include <gmem.h> // 'cos of GAllocPtrF etc.
  73. /************************************************************************/
  74. /*
  75. @doc INTERNAL MCIWAVE
  76. @func int | abs |
  77. This macro returns the absolute value of the signed integer passed to
  78. it.
  79. @parm int | x |
  80. Contains the integer whose absolute value is to be returned.
  81. @rdesc Returns the absolute value of the signed parameter passed.
  82. */
  83. #define abs(x) ((x) > 0 ? (x) : -(x))
  84. /************************************************************************/
  85. /*
  86. @doc INTERNAL MCIWAVE
  87. @func DWORD | mwFindThisFreeDataNode |
  88. Attempts to locate a free wave data node whose temporary data points to
  89. <p>dDataStart<d>. This allows data from one node to be expanded to
  90. adjacent free data of another node. Note that this depends upon any
  91. free data nodes that previously pointed to original data to have their
  92. total length zeroed when freed.
  93. @parm <t>PWAVEDESC<d> | pwd |
  94. Pointer to the wave device descriptor.
  95. @parm DWORD | dDataStart |
  96. Indicates the data start position to match.
  97. @rdesc Returns the free data node with adjacent free temporary data, else -1
  98. if there is none.
  99. */
  100. PRIVATE DWORD PASCAL NEAR mwFindThisFreeDataNode(
  101. PWAVEDESC pwd,
  102. DWORD dDataStart)
  103. {
  104. LPWAVEDATANODE lpwdn;
  105. DWORD dBlockNode;
  106. for (lpwdn = LPWDN(pwd, 0), dBlockNode = 0; dBlockNode < pwd->dWaveDataNodes; lpwdn++, dBlockNode++)
  107. if (ISFREEBLOCKNODE(lpwdn) && lpwdn->dTotalLength && (UNMASKDATASTART(lpwdn) == dDataStart))
  108. return dBlockNode;
  109. return (DWORD)-1;
  110. }
  111. /************************************************************************/
  112. /*
  113. @doc INTERNAL MCIWAVE
  114. @func DWORD | mwFindAnyFreeBlockNode |
  115. Locates a free node with no data attached. If there is none, it forces
  116. more to be allocated.
  117. @parm <t>PWAVEDESC<d> | pwd |
  118. Pointer to the wave device descriptor.
  119. @rdesc Returns a node with no data attached, else -1 if no memory is available.
  120. The node returned is marked as a free node, and need not be discarded if
  121. not used.
  122. */
  123. PRIVATE DWORD PASCAL NEAR mwFindAnyFreeBlockNode(
  124. PWAVEDESC pwd)
  125. {
  126. LPWAVEDATANODE lpwdn;
  127. DWORD dCurBlockNode;
  128. for (lpwdn = LPWDN(pwd, 0), dCurBlockNode = 0; dCurBlockNode < pwd->dWaveDataNodes; lpwdn++, dCurBlockNode++)
  129. if (ISFREEBLOCKNODE(lpwdn) && !lpwdn->dTotalLength)
  130. return dCurBlockNode;
  131. return mwAllocMoreBlockNodes(pwd);
  132. }
  133. /************************************************************************/
  134. /*
  135. @doc INTERNAL MCIWAVE
  136. @func BOOL | CopyBlockData |
  137. Copies <p>wLength<d> bytes of data pointed to by the <p>lpwdnSrc<d>
  138. node to the data pointed to by the <p>lpwdnDst<d> node, starting at
  139. <p>dSrc<d> to <p>dDst<d>.
  140. @parm <t>PWAVEDESC<d> | pwd |
  141. Pointer to the wave device descriptor.
  142. @parm <t>LPWAVEDATANODE<d> | lpwdnSrc |
  143. Points to the source node.
  144. @parm <t>LPWAVEDATANODE<d> | lpwdnDst |
  145. Points to the destination node.
  146. @parm DWORD | dSrc |
  147. Indicates the starting offset at which the data is located.
  148. @parm DWORD | dDst |
  149. Indicates the starting offset at which to place the data.
  150. @parm DWORD | dLength |
  151. Indicates the number of bytes of data to move.
  152. @rdesc Returns TRUE if the data was copied, else FALSE if no memory is
  153. available, or if a read or write error occured. If an error occurs,
  154. the task error state is set.
  155. @comm Note that this function will not compile with C 6.00A -Ox.
  156. */
  157. PRIVATE BOOL PASCAL NEAR CopyBlockData(
  158. PWAVEDESC pwd,
  159. LPWAVEDATANODE lpwdnSrc,
  160. LPWAVEDATANODE lpwdnDst,
  161. DWORD dSrc,
  162. DWORD dDst,
  163. DWORD dLength)
  164. {
  165. LPBYTE lpbBuffer;
  166. UINT wError;
  167. if (0 != (lpbBuffer = GlobalAlloc(GMEM_FIXED, dLength))) {
  168. if ((_llseek(pwd->hfTempBuffers, UNMASKDATASTART(lpwdnSrc) + dSrc, SEEK_SET) == -1)
  169. || ((DWORD)_lread(pwd->hfTempBuffers, lpbBuffer, (LONG)dLength) != dLength)
  170. || (_llseek(pwd->hfTempBuffers, UNMASKDATASTART(lpwdnDst) + dDst, SEEK_SET) == -1))
  171. wError = MCIERR_FILE_READ;
  172. else
  173. wError = ((DWORD)_lwrite(pwd->hfTempBuffers, lpbBuffer, (LONG)dLength) == dLength) ? 0 : MCIERR_FILE_WRITE;
  174. GlobalFree(lpbBuffer);
  175. } else
  176. wError = MCIERR_OUT_OF_MEMORY;
  177. if (wError) {
  178. pwd->wTaskError = wError;
  179. return FALSE;
  180. }
  181. return TRUE;
  182. }
  183. /************************************************************************/
  184. /*
  185. @doc INTERNAL MCIWAVE
  186. @func DWORD | mwSplitCurrentDataNode |
  187. Splits the current node at the current position, creating a new node
  188. to contain the rest of the data, and possibly creating a second node
  189. to hold data not aligned on a block boundary, in the case of temporary
  190. data. The new node returned will have free temporary data space
  191. attached that is at least <p>wMinDataLength<d> bytes in length.
  192. If the split point is at the start of the current node, then the new
  193. node is just inserted in front of the current node.
  194. If the split point is at the end of the data of the current node, then
  195. the new node is just inserted after the current node.
  196. Else the current node must actually be split. This means that a new
  197. block to point to the data after the split point is created. If the
  198. current node points to temporary data and the split point is not block
  199. aligned, then any extra data needs to be copied over to the new node
  200. that is being inserted. This is because all starting points for
  201. temporary data are block aligned. If this is not temporary data,
  202. then the starting and ending points can just be adjusted to the exact
  203. split point, instead of having to be block aligned.
  204. @parm <t>PWAVEDESC<d> | pwd |
  205. Pointer to the wave device descriptor.
  206. @parm DWORD | dMinDataLength |
  207. Indicates the minimum size of temporary data space that is to be
  208. available to the new data node returned.
  209. @rdesc Returns the new node after the split, which is linked to the point
  210. after the current position in the current node. This node becomes the
  211. current node. Returns -1 if no memory was available, or a file error
  212. occurred, in which case the task error code is set.
  213. */
  214. PRIVATE DWORD PASCAL NEAR mwSplitCurrentDataNode(
  215. PWAVEDESC pwd,
  216. DWORD dMinDataLength)
  217. {
  218. LPWAVEDATANODE lpwdn;
  219. LPWAVEDATANODE lpwdnNew;
  220. DWORD dNewDataNode;
  221. DWORD dSplitAtData;
  222. BOOL fTempData;
  223. dSplitAtData = pwd->dCur - pwd->dVirtualWaveDataStart;
  224. lpwdn = LPWDN(pwd, pwd->dWaveDataCurrentNode);
  225. fTempData = ISTEMPDATA(lpwdn);
  226. if (fTempData)
  227. dMinDataLength += pwd->dAudioBufferLen;
  228. dNewDataNode = mwFindAnyFreeDataNode(pwd, dMinDataLength);
  229. if (dNewDataNode == -1)
  230. return (DWORD)-1;
  231. lpwdnNew = LPWDN(pwd, dNewDataNode);
  232. if (!dSplitAtData) {
  233. if (pwd->dWaveDataCurrentNode == pwd->dWaveDataStartNode)
  234. pwd->dWaveDataStartNode = dNewDataNode;
  235. else {
  236. LPWAVEDATANODE lpwdnCur;
  237. for (lpwdnCur = LPWDN(pwd, pwd->dWaveDataStartNode); lpwdnCur->dNextWaveDataNode != pwd->dWaveDataCurrentNode; lpwdnCur = LPWDN(pwd, lpwdnCur->dNextWaveDataNode))
  238. ;
  239. lpwdnCur->dNextWaveDataNode = dNewDataNode;
  240. }
  241. lpwdnNew->dNextWaveDataNode = pwd->dWaveDataCurrentNode;
  242. } else if (dSplitAtData == lpwdn->dDataLength) {
  243. lpwdnNew->dNextWaveDataNode = lpwdn->dNextWaveDataNode;
  244. lpwdn->dNextWaveDataNode = dNewDataNode;
  245. pwd->dVirtualWaveDataStart += lpwdn->dDataLength;
  246. } else {
  247. DWORD dEndBlockNode;
  248. LPWAVEDATANODE lpwdnEnd;
  249. DWORD dSplitPoint;
  250. if ((dEndBlockNode = mwFindAnyFreeBlockNode(pwd)) == -1) {
  251. RELEASEBLOCKNODE(lpwdnNew);
  252. return (DWORD)-1;
  253. }
  254. lpwdnEnd = LPWDN(pwd, dEndBlockNode);
  255. if (fTempData) {
  256. dSplitPoint = ROUNDDATA(pwd, dSplitAtData);
  257. if (dSplitPoint != dSplitAtData) {
  258. if (!CopyBlockData(pwd, lpwdn, lpwdnNew, dSplitAtData, 0, dSplitPoint - dSplitAtData)) {
  259. RELEASEBLOCKNODE(lpwdnNew);
  260. return (DWORD)-1;
  261. }
  262. lpwdnNew->dDataLength = dSplitPoint - dSplitAtData;
  263. }
  264. } else
  265. dSplitPoint = dSplitAtData;
  266. lpwdnEnd->dNextWaveDataNode = lpwdn->dNextWaveDataNode;
  267. lpwdnEnd->dDataStart = lpwdn->dDataStart + dSplitPoint;
  268. lpwdnEnd->dDataLength = lpwdn->dDataLength - dSplitPoint;
  269. lpwdnEnd->dTotalLength = lpwdn->dTotalLength - dSplitPoint;
  270. lpwdnNew->dNextWaveDataNode = dEndBlockNode;
  271. lpwdn->dDataLength = dSplitAtData;
  272. lpwdn->dTotalLength = dSplitPoint;
  273. lpwdn->dNextWaveDataNode = dNewDataNode;
  274. pwd->dVirtualWaveDataStart += lpwdn->dDataLength;
  275. }
  276. pwd->dWaveDataCurrentNode = dNewDataNode;
  277. return dNewDataNode;
  278. }
  279. /************************************************************************/
  280. /*
  281. @doc INTERNAL MCIWAVE
  282. @func DWORD | GatherAdjacentFreeDataNodes |
  283. This function is used to attempt to consolidate adjacent temporary
  284. data pointed to by free nodes so that a write can place data into
  285. a single node. This is done by repeatedly requesting any free data
  286. node whose data points to the end of the node's data passed.
  287. @parm <t>PWAVEDESC<d> | pwd |
  288. Pointer to the wave device descriptor.
  289. @parm <t>LPWAVEDATANODE<d> | lpwdn |
  290. Points to the node which is to collect adjacent temporary data.
  291. @parm DWORD | dStartPoint |
  292. Indicates the starting point to use when calculating the amount of
  293. data retrieved. This is just subtracted from the total length of
  294. the data attached to the node.
  295. @parm DWORD | dBufferLength |
  296. Indicates the amount of data to retrieve.
  297. @rdesc Returns the amount of data actually retrieved, adjusted by
  298. <d>dStartPoint<d>.
  299. */
  300. PRIVATE DWORD PASCAL NEAR GatherAdjacentFreeDataNodes(
  301. PWAVEDESC pwd,
  302. LPWAVEDATANODE lpwdn,
  303. DWORD dStartPoint,
  304. DWORD dBufferLength)
  305. {
  306. for (; lpwdn->dTotalLength - dStartPoint < dBufferLength;) {
  307. DWORD dFreeDataNode;
  308. LPWAVEDATANODE lpwdnFree;
  309. dFreeDataNode = mwFindThisFreeDataNode(pwd, UNMASKDATASTART(lpwdn) + lpwdn->dTotalLength);
  310. if (dFreeDataNode == -1)
  311. break;
  312. lpwdnFree = LPWDN(pwd, dFreeDataNode);
  313. lpwdn->dTotalLength += lpwdnFree->dTotalLength;
  314. lpwdnFree->dTotalLength = 0;
  315. }
  316. return min(dBufferLength, lpwdn->dTotalLength - dStartPoint);
  317. }
  318. /************************************************************************/
  319. /*
  320. @doc INTERNAL MCIWAVE
  321. @func <t>LPWAVEDATANODE<d> | NextDataNode |
  322. Locates a free data node with the specified amount of data, and inserts
  323. it after the current node, setting the current node to be this new
  324. node.
  325. @parm <t>PWAVEDESC<d> | pwd |
  326. Pointer to the wave device descriptor.
  327. @parm DWORD | dBufferLength |
  328. Indicates the minimum amount of data that is to be available to the
  329. new node inserted.
  330. @rdesc Returns the newly inserted node, else NULL on error, in which case the
  331. task error code is set.
  332. */
  333. PRIVATE LPWAVEDATANODE PASCAL NEAR NextDataNode(
  334. PWAVEDESC pwd,
  335. DWORD dBufferLength)
  336. {
  337. DWORD dWaveDataNew;
  338. LPWAVEDATANODE lpwdn;
  339. LPWAVEDATANODE lpwdnNew;
  340. if ((dWaveDataNew = mwFindAnyFreeDataNode(pwd, dBufferLength)) == -1)
  341. return NULL;
  342. lpwdn = LPWDN(pwd, pwd->dWaveDataCurrentNode);
  343. lpwdnNew = LPWDN(pwd, dWaveDataNew);
  344. lpwdnNew->dNextWaveDataNode = lpwdn->dNextWaveDataNode;
  345. lpwdn->dNextWaveDataNode = dWaveDataNew;
  346. pwd->dWaveDataCurrentNode = dWaveDataNew;
  347. pwd->dVirtualWaveDataStart += lpwdn->dDataLength;
  348. return lpwdnNew;
  349. }
  350. /************************************************************************/
  351. /*
  352. @doc INTERNAL MCIWAVE
  353. @func BOOL | AdjustLastTempData |
  354. This function makes two passes through the nodes that are affected by
  355. an overwrite record. These are nodes that are either no longer needed,
  356. or whose starting point needs to be adjusted. The two passes allow
  357. any data to be successfully copied before removing any unneeded nodes.
  358. This creates a more graceful exit to any failure.
  359. The first pass locates the last node affected. If that node points to
  360. temporary data, and the end of the overwrite does not fall on a block
  361. aligned boundary, then any extra data must be copied to a block aligned
  362. boundary. This means that a new node might need to be created if the
  363. amount of data to be copied is greater than one block's worth. If the
  364. end of overwrite happens to fall on a block boundary, then no copying
  365. need be done. In either case the data start point is adjusted to
  366. compensate for the data logically overwritten in this node, and the
  367. total overwrite length is adjusted so that this node is not checked on
  368. the second pass.
  369. The second pass just frees nodes that become empty, and removes them
  370. from the linked list of in-use nodes. When the last node affected is
  371. encountered, either it will point to temporary data, in which case be
  372. already adjusted, or point to original data, which must be adjusted.
  373. @parm <t>PWAVEDESC<d> | pwd |
  374. Pointer to the wave device descriptor.
  375. @parm <t>LPWAVEDATANODE<d> | lpwdn |
  376. Points to the node which is being adjusted for. It contains the new
  377. data.
  378. @parm DWORD | dStartPoint |
  379. Contains the starting point at which data was overwritten.
  380. @parm DWORD | dWriteSize |
  381. Contains the amount of data overwritten.
  382. @rdesc Returns TRUE if the nothing needed to be adjusted, or the last node
  383. in the overwrite pointed to temporary data, and it was moved correctly,
  384. else FALSE if no memory was available, or a file error occurred. In
  385. that case the task error code is set.
  386. */
  387. PRIVATE BOOL PASCAL NEAR AdjustLastTempData(
  388. PWAVEDESC pwd,
  389. LPWAVEDATANODE lpwdn,
  390. DWORD dStartPoint,
  391. DWORD dWriteSize)
  392. {
  393. LPWAVEDATANODE lpwdnCur;
  394. DWORD dLength;
  395. if ((lpwdn->dDataLength - dStartPoint >= dWriteSize) || (lpwdn->dNextWaveDataNode == ENDOFNODES))
  396. return TRUE;
  397. dWriteSize -= (lpwdn->dDataLength - dStartPoint);
  398. for (dLength = dWriteSize, lpwdnCur = lpwdn;;) {
  399. LPWAVEDATANODE lpwdnNext;
  400. lpwdnNext = LPWDN(pwd, lpwdnCur->dNextWaveDataNode);
  401. if (lpwdnNext->dDataLength >= dLength) {
  402. DWORD dNewBlockNode;
  403. DWORD dMoveData;
  404. if (!ISTEMPDATA(lpwdnNext) || (lpwdnNext->dDataLength == dLength))
  405. break;
  406. if (lpwdnNext->dDataLength - dLength > ROUNDDATA(pwd, 1)) {
  407. if ((dNewBlockNode = mwFindAnyFreeBlockNode(pwd)) == -1)
  408. return FALSE;
  409. } else
  410. dNewBlockNode = (DWORD)-1;
  411. dMoveData = min(ROUNDDATA(pwd, dLength), lpwdnNext->dDataLength) - dLength;
  412. if (dMoveData && !CopyBlockData(pwd, lpwdnNext, lpwdnNext, dLength, 0, dMoveData))
  413. return FALSE;
  414. if (dNewBlockNode != -1) {
  415. lpwdnCur = LPWDN(pwd, dNewBlockNode);
  416. lpwdnCur->dDataStart = lpwdnNext->dDataStart + dLength + dMoveData;
  417. lpwdnCur->dDataLength = lpwdnNext->dDataLength - (dLength + dMoveData);
  418. lpwdnCur->dTotalLength = lpwdnNext->dTotalLength - (dLength + dMoveData);
  419. lpwdnCur->dNextWaveDataNode = lpwdnNext->dNextWaveDataNode;
  420. lpwdnNext->dNextWaveDataNode = dNewBlockNode;
  421. lpwdnNext->dTotalLength = dLength + dMoveData;
  422. }
  423. lpwdnNext->dDataLength = dMoveData;
  424. dWriteSize -= dLength;
  425. break;
  426. } else if ((!ISTEMPDATA(lpwdnNext)) && (lpwdnNext->dNextWaveDataNode == ENDOFNODES))
  427. break;
  428. dLength -= lpwdnNext->dDataLength;
  429. lpwdnCur = lpwdnNext;
  430. }
  431. for (;;) {
  432. LPWAVEDATANODE lpwdnNext;
  433. lpwdnNext = LPWDN(pwd, lpwdn->dNextWaveDataNode);
  434. if (lpwdnNext->dDataLength > dWriteSize) {
  435. if (dWriteSize) {
  436. lpwdnNext->dDataStart += dWriteSize;
  437. lpwdnNext->dDataLength -= dWriteSize;
  438. lpwdnNext->dTotalLength -= dWriteSize;
  439. }
  440. return TRUE;
  441. }
  442. dWriteSize -= lpwdnNext->dDataLength;
  443. lpwdn->dNextWaveDataNode = lpwdnNext->dNextWaveDataNode;
  444. if (!ISTEMPDATA(lpwdnNext))
  445. lpwdnNext->dTotalLength = 0;
  446. RELEASEBLOCKNODE(lpwdnNext);
  447. if (lpwdn->dNextWaveDataNode == ENDOFNODES)
  448. return TRUE;
  449. }
  450. }
  451. /************************************************************************/
  452. /*
  453. @doc INTERNAL MCIWAVE
  454. @func BOOL | mwOverWrite |
  455. This function overwrites data in the wave file from the specified wave
  456. buffer. The position is taken from the <e>WAVEDESC.dCur<d> pointer,
  457. which is updated with the number of bytes actually overwritten.
  458. @parm <t>PWAVEDESC<d> | pwd |
  459. Pointer to the wave device descriptor.
  460. @parm LPBYTE | lpbBuffer |
  461. Points to a buffer to containing the data written.
  462. @parm DWORD | dBufferLength |
  463. Indicates the byte length of the buffer.
  464. @rdesc Returns TRUE if overwrite succeeded, else FALSE on an error.
  465. */
  466. PRIVATE BOOL PASCAL NEAR mwOverWrite(
  467. PWAVEDESC pwd,
  468. LPBYTE lpbBuffer,
  469. DWORD dBufferLength)
  470. {
  471. LPWAVEDATANODE lpwdn;
  472. lpwdn = LPWDN(pwd, pwd->dWaveDataCurrentNode);
  473. for (; dBufferLength;)
  474. if (ISTEMPDATA(lpwdn)) {
  475. DWORD dStartPoint;
  476. DWORD dRemainingSpace;
  477. DWORD dMaxWrite;
  478. dStartPoint = pwd->dCur - pwd->dVirtualWaveDataStart;
  479. dRemainingSpace = min(dBufferLength, lpwdn->dTotalLength - dStartPoint);
  480. if (dRemainingSpace == dBufferLength)
  481. dMaxWrite = dBufferLength;
  482. else if (UNMASKDATASTART(lpwdn) + lpwdn->dTotalLength == pwd->dWaveTempDataLength) {
  483. dMaxWrite = dBufferLength;
  484. lpwdn->dTotalLength += ROUNDDATA(pwd, dBufferLength - dRemainingSpace);
  485. pwd->dWaveTempDataLength += ROUNDDATA(pwd, dBufferLength - dRemainingSpace);
  486. } else
  487. dMaxWrite = GatherAdjacentFreeDataNodes(pwd, lpwdn, dStartPoint, dBufferLength);
  488. if (dMaxWrite) {
  489. DWORD dWriteSize;
  490. if (_llseek(pwd->hfTempBuffers, UNMASKDATASTART(lpwdn) + dStartPoint, SEEK_SET) == -1) {
  491. pwd->wTaskError = MCIERR_FILE_WRITE;
  492. break;
  493. }
  494. dWriteSize = (DWORD)_lwrite(pwd->hfTempBuffers, lpbBuffer, (LONG)dMaxWrite);
  495. if (dWriteSize != -1) {
  496. if (!AdjustLastTempData(pwd, lpwdn, dStartPoint, dWriteSize))
  497. break;
  498. if (lpwdn->dDataLength < dStartPoint + dWriteSize)
  499. lpwdn->dDataLength = dStartPoint + dWriteSize;
  500. lpbBuffer += dWriteSize;
  501. dBufferLength -= dWriteSize;
  502. pwd->dCur += dWriteSize;
  503. if (pwd->dVirtualWaveDataStart + lpwdn->dDataLength > pwd->dSize)
  504. pwd->dSize = pwd->dVirtualWaveDataStart + lpwdn->dDataLength;
  505. }
  506. if (dWriteSize != dMaxWrite) {
  507. pwd->wTaskError = MCIERR_FILE_WRITE;
  508. break;
  509. }
  510. }
  511. if (dBufferLength && !(lpwdn = NextDataNode(pwd, dBufferLength)))
  512. break;
  513. } else {
  514. DWORD dWaveDataNew;
  515. if ((dWaveDataNew = mwSplitCurrentDataNode(pwd, dBufferLength)) != -1)
  516. lpwdn = LPWDN(pwd, dWaveDataNew);
  517. else
  518. break;
  519. }
  520. return !dBufferLength;
  521. }
  522. /************************************************************************/
  523. /*
  524. @doc INTERNAL MCIWAVE
  525. @func BOOL | mwInsert |
  526. This function inserts data to the wave file from the specified wave
  527. buffer. The position is taken from the <e>WAVEDESC.dCur<d> pointer,
  528. which is updated with the number of bytes actually written.
  529. @parm <t>PWAVEDESC<d> | pwd |
  530. Pointer to the wave device descriptor.
  531. @parm LPBYTE | lpbBuffer |
  532. Points to a buffer to containing the data written.
  533. @parm DWORD | dBufferLength |
  534. Indicates the byte length of the buffer.
  535. @rdesc Returns TRUE if insert succeeded, else FALSE on an error.
  536. */
  537. PRIVATE BOOL PASCAL NEAR mwInsert(
  538. PWAVEDESC pwd,
  539. LPBYTE lpbBuffer,
  540. DWORD dBufferLength)
  541. {
  542. LPWAVEDATANODE lpwdn;
  543. lpwdn = LPWDN(pwd, pwd->dWaveDataCurrentNode);
  544. for (; dBufferLength;)
  545. if (ISTEMPDATA(lpwdn) && (pwd->dCur == pwd->dVirtualWaveDataStart + lpwdn->dDataLength)) {
  546. DWORD dStartPoint;
  547. DWORD dRemainingSpace;
  548. DWORD dMaxInsert;
  549. dStartPoint = pwd->dCur - pwd->dVirtualWaveDataStart;
  550. dRemainingSpace = min(dBufferLength, lpwdn->dTotalLength - lpwdn->dDataLength);
  551. if (dRemainingSpace == dBufferLength)
  552. dMaxInsert = dBufferLength;
  553. else if (UNMASKDATASTART(lpwdn) + lpwdn->dTotalLength == pwd->dWaveTempDataLength) {
  554. dMaxInsert = dBufferLength;
  555. lpwdn->dTotalLength += ROUNDDATA(pwd, dBufferLength - dRemainingSpace);
  556. pwd->dWaveTempDataLength += ROUNDDATA(pwd, dBufferLength - dRemainingSpace);
  557. } else
  558. dMaxInsert = GatherAdjacentFreeDataNodes(pwd, lpwdn, dStartPoint, dBufferLength);
  559. if (dMaxInsert) {
  560. DWORD dWriteSize;
  561. if (_llseek(pwd->hfTempBuffers, UNMASKDATASTART(lpwdn) + dStartPoint, SEEK_SET) == -1) {
  562. pwd->wTaskError = MCIERR_FILE_WRITE;
  563. break;
  564. }
  565. dWriteSize = (DWORD)_lwrite(pwd->hfTempBuffers, lpbBuffer, (LONG)dMaxInsert);
  566. if (dWriteSize != -1) {
  567. lpwdn->dDataLength += dWriteSize;
  568. lpbBuffer += dWriteSize;
  569. dBufferLength -= dWriteSize;
  570. pwd->dCur += dWriteSize;
  571. pwd->dSize += dWriteSize;
  572. }
  573. if (dWriteSize != dMaxInsert) {
  574. pwd->wTaskError = MCIERR_FILE_WRITE;
  575. break;
  576. }
  577. }
  578. if (dBufferLength && !(lpwdn = NextDataNode(pwd, dBufferLength)))
  579. break;
  580. } else {
  581. DWORD dWaveDataNew;
  582. if ((dWaveDataNew = mwSplitCurrentDataNode(pwd, dBufferLength)) != -1)
  583. lpwdn = LPWDN(pwd, dWaveDataNew);
  584. else
  585. break;
  586. }
  587. return !dBufferLength;
  588. }
  589. /************************************************************************/
  590. /*
  591. @doc INTERNAL MCIWAVE
  592. @func DWORD | mwGetLevel |
  593. This function finds the highest level in the specified wave sample.
  594. Note that the function assumes that in some cases the sample size
  595. is evenly divisable by 4.
  596. @parm <t>PWAVEDESC<d> | pwd |
  597. Pointer to the wave device descriptor.
  598. @parm LPBYTE | lpbBuffer |
  599. Points to a buffer containing the sample whose highest level is to be
  600. returned.
  601. @parm int | cbBufferLength |
  602. Indicates the byte length of the sample buffer.
  603. @rdesc Returns the highest level encountered in the sample for PCM data only.
  604. If the device has been opened with one channel, the level is contained
  605. in the low-order word. Else if the device has been opened with two
  606. channels, one channel is in the low-order word, and the other is in the
  607. high-order word.
  608. */
  609. PRIVATE DWORD PASCAL NEAR mwGetLevel(
  610. PWAVEDESC pwd,
  611. LPBYTE lpbBuffer,
  612. register int cbBufferLength)
  613. {
  614. if (pwd->pwavefmt->wFormatTag != WAVE_FORMAT_PCM)
  615. return 0;
  616. else if (pwd->pwavefmt->nChannels == 1) {
  617. int iMonoLevel;
  618. iMonoLevel = 0;
  619. if (((NPPCMWAVEFORMAT)(pwd->pwavefmt))->wBitsPerSample == 8)
  620. for (; cbBufferLength--; lpbBuffer++)
  621. iMonoLevel = max(*lpbBuffer > 128 ? *lpbBuffer - 128 : 128 - *lpbBuffer, iMonoLevel);
  622. else if (((NPPCMWAVEFORMAT)(pwd->pwavefmt))->wBitsPerSample == 16)
  623. for (; cbBufferLength; lpbBuffer += sizeof(SHORT)) {
  624. iMonoLevel = max(abs(*(PSHORT)lpbBuffer), iMonoLevel);
  625. cbBufferLength -= sizeof(SHORT);
  626. }
  627. else
  628. return 0;
  629. return (DWORD)iMonoLevel;
  630. } else if (pwd->pwavefmt->nChannels == 2) {
  631. int iLeftLevel;
  632. int iRightLevel;
  633. iLeftLevel = 0;
  634. iRightLevel = 0;
  635. if (((NPPCMWAVEFORMAT)(pwd->pwavefmt))->wBitsPerSample == 8)
  636. for (; cbBufferLength;) {
  637. iLeftLevel = max(*lpbBuffer > 128 ? *lpbBuffer - 128 : 128 - *lpbBuffer, iLeftLevel);
  638. lpbBuffer++;
  639. iRightLevel = max(*lpbBuffer > 128 ? *lpbBuffer - 128 : 128 - *lpbBuffer, iRightLevel);
  640. lpbBuffer++;
  641. cbBufferLength -= 2;
  642. }
  643. else if (((NPPCMWAVEFORMAT)(pwd->pwavefmt))->wBitsPerSample == 16)
  644. for (; cbBufferLength;) {
  645. iLeftLevel = max(abs(*(PSHORT)lpbBuffer), iLeftLevel);
  646. lpbBuffer += sizeof(SHORT);
  647. iRightLevel = max(abs(*(PSHORT)lpbBuffer), iRightLevel);
  648. lpbBuffer += sizeof(SHORT);
  649. cbBufferLength -= 2 * sizeof(SHORT);
  650. }
  651. else
  652. return 0;
  653. return MAKELONG(iLeftLevel, iRightLevel);
  654. }
  655. return 0;
  656. }
  657. /************************************************************************/
  658. /*
  659. @doc INTERNAL MCIWAVE
  660. @func BOOL | CheckNewCommand |
  661. This function is called when a New command flag is found during the
  662. record loop. It determines if the new commands affect current
  663. recording enough that it must be terminated. This can happen if a
  664. Stop command is received.
  665. Any other record change does not need to stop current recording, as
  666. they should just release all the buffers from the wave device before
  667. setting the command.
  668. @parm <t>PWAVEDESC<d> | pwd |
  669. Pointer to the wave device descriptor.
  670. @rdesc Returns TRUE if the new commands do not affect recording and it should
  671. continue, else FALSE if the new commands affect the recording, and it
  672. should be aborted.
  673. */
  674. REALLYPRIVATE BOOL PASCAL NEAR CheckNewCommand(
  675. PWAVEDESC pwd)
  676. {
  677. if (ISMODE(pwd, COMMAND_STOP))
  678. return FALSE;
  679. if (ISMODE(pwd, COMMAND_INSERT))
  680. ADDMODE(pwd, MODE_INSERT);
  681. else
  682. ADDMODE(pwd, MODE_OVERWRITE);
  683. REMOVEMODE(pwd, COMMAND_NEW);
  684. return TRUE;
  685. }
  686. /************************************************************************/
  687. /*
  688. @doc INTERNAL MCIWAVE
  689. @func <t>HMMIO<d> | CreateSaveFile |
  690. This function creates the file to which the current data is to be
  691. saved to in RIFF format. This is either a temporary file created on
  692. the same logical disk as the original file (so that this file can
  693. replace the original file), else a new file.
  694. The RIFF header and wave header chunks are written to the new file,
  695. and the file position is at the start of the data to be copied. Note
  696. that all the RIFF chunk headers will contain correct lengths, so there
  697. is no need to ascend out of the data chunk when complete.
  698. @parm <t>PWAVEDESC<d> | pwd |
  699. Pointer to the wave device descriptor.
  700. @parm SSZ | sszTempSaveFile |
  701. Points to a buffer to contain the name of the temporary file created,
  702. if any. This is zero length if a new file is to be created instead of
  703. a temporary file that would replace the original file.
  704. @rdesc Returns the handle to the save file, else NULL if a create error or
  705. write error occurred.
  706. @comm Note that this needs to be fixed so that non-DOS IO systems can save
  707. the file to the original name by creating a temporary file name through
  708. MMIO.
  709. */
  710. PRIVATE HMMIO PASCAL NEAR CreateSaveFile(
  711. PWAVEDESC pwd,
  712. LPWSTR sszTempSaveFile)
  713. {
  714. MMIOINFO mmioInfo;
  715. HMMIO hmmio;
  716. LPWSTR lszFile;
  717. InitMMIOOpen(pwd, &mmioInfo);
  718. if (pwd->szSaveFile) {
  719. *sszTempSaveFile = (char)0;
  720. lszFile = pwd->szSaveFile;
  721. } else {
  722. lstrcpy(sszTempSaveFile, pwd->aszFile);
  723. if (!mmioOpen(sszTempSaveFile, &mmioInfo, MMIO_GETTEMP)) {
  724. pwd->wTaskError = MCIERR_FILE_WRITE;
  725. return NULL;
  726. }
  727. lszFile = sszTempSaveFile;
  728. }
  729. if (0 != (hmmio = mmioOpen(lszFile, &mmioInfo, MMIO_CREATE | MMIO_READWRITE | MMIO_DENYWRITE))) {
  730. MMCKINFO mmck;
  731. mmck.cksize = sizeof(FOURCC) + sizeof(FOURCC) + sizeof(DWORD) + pwd->wFormatSize + sizeof(FOURCC) + sizeof(DWORD) + pwd->dSize;
  732. if (pwd->wFormatSize & 1)
  733. mmck.cksize++;
  734. mmck.fccType = mmioWAVE;
  735. if (!mmioCreateChunk(hmmio, &mmck, MMIO_CREATERIFF)) {
  736. mmck.cksize = pwd->wFormatSize;
  737. mmck.ckid = mmioFMT;
  738. if (!mmioCreateChunk(hmmio, &mmck, 0) && (mmioWrite(hmmio, (LPSTR)pwd->pwavefmt, (LONG)pwd->wFormatSize) == (LONG)pwd->wFormatSize) && !mmioAscend(hmmio, &mmck, 0)) {
  739. mmck.cksize = pwd->dSize;
  740. mmck.ckid = mmioDATA;
  741. if (!mmioCreateChunk(hmmio, &mmck, 0))
  742. return hmmio;
  743. }
  744. }
  745. pwd->wTaskError = MCIERR_FILE_WRITE;
  746. mmioClose(hmmio, 0);
  747. } else
  748. pwd->wTaskError = MCIERR_FILE_NOT_SAVED;
  749. return NULL;
  750. }
  751. /************************************************************************/
  752. /*
  753. @doc INTERNAL MCIWAVE
  754. @func VOID | mwSaveData |
  755. This function is used by the background task to save the data to a
  756. specified file. This has the effect of making all the temporary data
  757. now original data, and removing any temporary data file.
  758. @parm <t>PWAVEDESC<d> | pwd |
  759. Pointer to the wave device descriptor.
  760. @rdesc Nothing.
  761. */
  762. PUBLIC VOID PASCAL FAR mwSaveData(
  763. PWAVEDESC pwd)
  764. {
  765. LPBYTE lpbBuffer = NULL;
  766. HANDLE hMem;
  767. DWORD AllocSize = max(min(pwd->dAudioBufferLen, pwd->dSize),1);
  768. // If there is no wave data, we still allocate 1 byte in order to save a NULL
  769. // file. Otherwise we have no choice but to return an error saying "Out of memory"
  770. hMem = GlobalAlloc(GMEM_MOVEABLE, AllocSize);
  771. if (hMem) {
  772. lpbBuffer = GlobalLock(hMem);
  773. dprintf3(("mwSaveData allocated %d bytes at %8x, handle %8x",
  774. AllocSize, lpbBuffer, hMem));
  775. dprintf3(("pwd->AudioBufferLen = %d, pwd->dSize = %d",
  776. pwd->dAudioBufferLen, pwd->dSize));
  777. }
  778. if (lpbBuffer) {
  779. WCHAR aszTempSaveFile[_MAX_PATH];
  780. HMMIO hmmioSave;
  781. if (0 != (hmmioSave = CreateSaveFile(pwd, (SSZ)aszTempSaveFile))) {
  782. LPWAVEDATANODE lpwdn;
  783. lpwdn = LPWDN(pwd, pwd->dWaveDataStartNode);
  784. for (;;) {
  785. DWORD dDataLength;
  786. BOOL fTempData;
  787. fTempData = ISTEMPDATA(lpwdn);
  788. if (fTempData)
  789. _llseek(pwd->hfTempBuffers, UNMASKDATASTART(lpwdn), SEEK_SET);
  790. else
  791. mmioSeek(pwd->hmmio, pwd->dRiffData + lpwdn->dDataStart, SEEK_SET);
  792. for (dDataLength = lpwdn->dDataLength; dDataLength;) {
  793. DWORD dReadSize;
  794. dReadSize = min(pwd->dAudioBufferLen, dDataLength);
  795. if (dReadSize >= AllocSize) {
  796. dprintf(("READING TOO MUCH DATA!!"));
  797. }
  798. if (fTempData) {
  799. if ((DWORD)_lread(pwd->hfTempBuffers, lpbBuffer, (LONG)dReadSize) != dReadSize) {
  800. pwd->wTaskError = MCIERR_FILE_READ;
  801. break;
  802. }
  803. } else if ((DWORD)mmioRead(pwd->hmmio, lpbBuffer, (LONG)dReadSize) != dReadSize) {
  804. pwd->wTaskError = MCIERR_FILE_READ;
  805. break;
  806. }
  807. if ((DWORD)mmioWrite(hmmioSave, lpbBuffer, (LONG)dReadSize) != dReadSize) {
  808. pwd->wTaskError = MCIERR_FILE_WRITE;
  809. break;
  810. }
  811. dDataLength -= dReadSize;
  812. }
  813. if (pwd->wTaskError)
  814. break;
  815. if (lpwdn->dNextWaveDataNode == ENDOFNODES)
  816. break;
  817. lpwdn = LPWDN(pwd, lpwdn->dNextWaveDataNode);
  818. }
  819. mmioClose(hmmioSave, 0);
  820. if (!pwd->wTaskError) {
  821. MMIOINFO mmioInfo;
  822. MMCKINFO mmckRiff;
  823. MMCKINFO mmck;
  824. if (pwd->hmmio)
  825. mmioClose(pwd->hmmio, 0);
  826. InitMMIOOpen(pwd, &mmioInfo);
  827. if (pwd->szSaveFile)
  828. lstrcpy(pwd->aszFile, pwd->szSaveFile);
  829. else {
  830. if (!mmioOpen(pwd->aszFile, &mmioInfo, MMIO_DELETE))
  831. pwd->wTaskError = MCIERR_FILE_WRITE;
  832. if (!pwd->wTaskError)
  833. if (mmioRename(aszTempSaveFile, pwd->aszFile, &mmioInfo, 0)) {
  834. lstrcpy(pwd->aszFile, aszTempSaveFile);
  835. *aszTempSaveFile = (char)0;
  836. }
  837. }
  838. pwd->hmmio = mmioOpen(pwd->aszFile, &mmioInfo, MMIO_READ | MMIO_DENYWRITE);
  839. if (!pwd->wTaskError) {
  840. LPWAVEDATANODE lpwdn;
  841. mmckRiff.fccType = mmioWAVE;
  842. mmioDescend(pwd->hmmio, &mmckRiff, NULL, MMIO_FINDRIFF);
  843. mmck.ckid = mmioDATA;
  844. mmioDescend(pwd->hmmio, &mmck, &mmckRiff, MMIO_FINDCHUNK);
  845. pwd->dRiffData = mmck.dwDataOffset;
  846. if (pwd->hfTempBuffers != HFILE_ERROR) {
  847. _lclose(pwd->hfTempBuffers);
  848. pwd->dWaveTempDataLength = 0;
  849. DeleteFile( pwd->aszTempFile );
  850. pwd->hfTempBuffers = HFILE_ERROR;
  851. }
  852. if (pwd->lpWaveDataNode) {
  853. GlobalFreePtr(pwd->lpWaveDataNode);
  854. pwd->lpWaveDataNode = NULL;
  855. pwd->dWaveDataNodes = 0;
  856. }
  857. pwd->dVirtualWaveDataStart = 0;
  858. pwd->dWaveDataCurrentNode = 0;
  859. pwd->dWaveDataStartNode = 0;
  860. mwAllocMoreBlockNodes(pwd);
  861. lpwdn = LPWDN(pwd, 0);
  862. lpwdn->dNextWaveDataNode = (DWORD)ENDOFNODES;
  863. lpwdn->dDataLength = pwd->dSize;
  864. lpwdn->dTotalLength = pwd->dSize;
  865. if (!pwd->szSaveFile && !*aszTempSaveFile)
  866. pwd->wTaskError = MCIERR_FILE_WRITE;
  867. }
  868. }
  869. }
  870. GlobalUnlock(hMem);
  871. } else {
  872. pwd->wTaskError = MCIERR_OUT_OF_MEMORY;
  873. }
  874. if (hMem) {
  875. GlobalFree(hMem);
  876. }
  877. }
  878. /************************************************************************/
  879. /*
  880. @doc INTERNAL MCIWAVE
  881. @func VOID | mwDeleteData |
  882. This function is used by the background task to delete data.
  883. And that was a crappy non-spec! Specs should say what it has to do!
  884. I think it deletes data from pwd->dFrom upto but not including pwd->dTo.
  885. ????? Is there a pre-condition that pdw->dWaveDataCurrentNode must
  886. ????? point to the first node containing data to be deleted
  887. @parm <t>PWAVEDESC<d> | pwd |
  888. Pointer to the wave device descriptor.
  889. @rdesc Nothing.
  890. */
  891. PUBLIC VOID PASCAL FAR mwDeleteData(
  892. PWAVEDESC pwd)
  893. {
  894. DWORD dTotalToDelete;
  895. LPWAVEDATANODE lpwdn;
  896. LPWAVEDATANODE lpwdnCur;
  897. DWORD dVirtualWaveDataStart;
  898. DWORD dStartOffset; /* start of deletable section - start of block (<===> in picture)
  899. ** 0 for all except first node
  900. */
  901. /*
  902. ** pwd->dWaveDataCurrentNode
  903. ** \
  904. ** \
  905. ** \ pwd->dVirtualWaveDataStart
  906. ** \ |
  907. ** \ |
  908. ** \ |pwd->dFrom pwd->dTo
  909. ** \ | | |
  910. ** ---------- ---------- ------------ -------------- ----------
  911. ** | | | <----| |------------| |--------> | | |
  912. ** ---------- ---------- ------------ -------------- ----------
  913. ** node node node node node
  914. ** <===>
  915. ** |
  916. ** dStartOffset
  917. */
  918. /* ????? !! I'm woried about the WAVEDATANODE dDataStart fields.
  919. ?? Where do they get updated. Shouldn't ALL the nodes after the
  920. ?? deleted portion get this reduced by dDeleteLength
  921. ?? Does dDataStart refer to the position in the LOGICAL file (i.e. the
  922. ?? file made up by concatenating the sections identified by all the
  923. ?? bits that the WAVEDATANODEs identify, or does it refer to the PHYSICAL
  924. ?? position in one of the files (either the main or temporary file)
  925. ??
  926. ?? I'm pretty sure that this code is still broken.
  927. */
  928. lpwdn = LPWDN(pwd, pwd->dWaveDataCurrentNode);
  929. dTotalToDelete = pwd->dTo - pwd->dFrom;
  930. if (dTotalToDelete == pwd->dSize) {
  931. // The whole wave chunk is to be deleted - nice and simple
  932. DWORD dNewDataNode;
  933. if ((dNewDataNode = mwFindAnyFreeDataNode(pwd, 1)) == -1) {
  934. dprintf2(("mwDeleteData - no free data node"));
  935. return;
  936. }
  937. RELEASEBLOCKNODE(LPWDN(pwd, dNewDataNode));
  938. }
  939. dprintf3(("mwDeleteData - size to delete = %d", dTotalToDelete));
  940. /* step lpwdn (already pointing at the current node) through nodes deleting
  941. what's available until we have deleted dTotalToDelete. First and last
  942. nodes visited may need special treatment. Don't delete before dFrom in first,
  943. don't delete beyond the required amount in the last
  944. */
  945. dVirtualWaveDataStart = pwd->dVirtualWaveDataStart;
  946. dStartOffset = pwd->dFrom - dVirtualWaveDataStart;
  947. while (dTotalToDelete>0) {
  948. DWORD dDeleteLength;
  949. DWORD dStartOff = dStartOffset; /* we need a copy of the old value of dStartoffset */
  950. dStartOffset = 0;
  951. dDeleteLength = min(dTotalToDelete, lpwdn->dDataLength - dStartOff);
  952. dprintf4(("mwDelete dTotalToDelete = %d, dDeleteLength = %d", dTotalToDelete, dDeleteLength));
  953. if (dDeleteLength==0) {
  954. // Nothing to be deleted from this block
  955. dprintf3(("mwDelete skipping to next block"));
  956. dVirtualWaveDataStart += lpwdn->dDataLength;
  957. lpwdn = LPWDN(pwd, lpwdn->dNextWaveDataNode);
  958. continue; // iterate around the while loop
  959. }
  960. // Note: the block above is new to NT. Windows 3.1 as shipped fails.
  961. // The problem can be seen with a wave file > 3 seconds long and
  962. // the following two commands:
  963. // delete wave from 1000 to 2000
  964. // delete wave from 1000 to 2000
  965. // Because of the fragmentation the second delete fails. It decided
  966. // that NO data can be deleted from the first block, but never
  967. // stepped on to the next block.
  968. if (ISTEMPDATA(lpwdn)) {
  969. dprintf3(("mwDeleteData - temporary data"));
  970. if (dVirtualWaveDataStart + lpwdn->dDataLength <= pwd->dFrom + dTotalToDelete)
  971. /* the delete goes to or beyond the end of this block */
  972. lpwdn->dDataLength -= dDeleteLength; // Delete data in this block
  973. else { /* the delete stops in the middle of this block */
  974. DWORD dNewBlockNode;
  975. DWORD dEndSplitPoint;
  976. DWORD dMoveData;
  977. dEndSplitPoint = min(ROUNDDATA(pwd, dStartOff + dDeleteLength), lpwdn->dDataLength);
  978. if (dEndSplitPoint < lpwdn->dDataLength) {
  979. if ((dNewBlockNode = mwFindAnyFreeBlockNode(pwd)) == -1)
  980. break;
  981. } else
  982. dNewBlockNode = (DWORD)-1;
  983. dMoveData = dEndSplitPoint - (dStartOff + dDeleteLength);
  984. if (dMoveData && !CopyBlockData(pwd, lpwdn, lpwdn, dStartOff + dDeleteLength, dStartOff, dMoveData))
  985. break;
  986. if (dNewBlockNode != -1) {
  987. lpwdnCur = LPWDN(pwd, dNewBlockNode);
  988. lpwdnCur->dDataStart = lpwdn->dDataStart + dEndSplitPoint;
  989. lpwdnCur->dDataLength = lpwdn->dDataLength - dEndSplitPoint;
  990. lpwdnCur->dTotalLength = lpwdn->dTotalLength - dEndSplitPoint;
  991. lpwdnCur->dNextWaveDataNode = lpwdn->dNextWaveDataNode;
  992. lpwdn->dNextWaveDataNode = dNewBlockNode;
  993. lpwdn->dTotalLength = dEndSplitPoint;
  994. }
  995. lpwdn->dDataLength = dStartOff + dMoveData;
  996. }
  997. } else if (0==dStartOff) {
  998. // Deleting from the beginning of this node. We can
  999. // simply adjust the total length and start point.
  1000. dprintf4(("mwDeleteData - From == Start, deleting from start of block"));
  1001. lpwdn->dDataStart += dDeleteLength;
  1002. lpwdn->dDataLength -= dDeleteLength;
  1003. lpwdn->dTotalLength = lpwdn->dDataLength;
  1004. } else if (dVirtualWaveDataStart + lpwdn->dDataLength <= pwd->dFrom + dTotalToDelete) {
  1005. // FROM point plus amount to delete takes us to the end of the wave
  1006. // data - meaning that the data block can be truncated. We can
  1007. // simply adjust the total length.
  1008. dprintf4(("mwDeleteData - delete to end of block"));
  1009. lpwdn->dDataLength -= dDeleteLength;
  1010. lpwdn->dTotalLength = lpwdn->dDataLength;
  1011. } else {
  1012. // We have to delete a chunk out of the middle.
  1013. DWORD dNewBlockNode;
  1014. // The existing single block will now be covered by two blocks
  1015. // Find a new node, then set the current node start->deletefrom
  1016. // and the new node deletefrom+deletelength for the remaining
  1017. // length of this node. It all hinges on finding a free node...
  1018. if ((dNewBlockNode = mwFindAnyFreeBlockNode(pwd)) == -1) {
  1019. dprintf2(("mwDeleteData - cannot find free node"));
  1020. break;
  1021. }
  1022. lpwdnCur = LPWDN(pwd, dNewBlockNode);
  1023. lpwdnCur->dDataStart = dVirtualWaveDataStart + dStartOff + dDeleteLength;
  1024. lpwdnCur->dDataLength = lpwdn->dDataLength - (dStartOff + dDeleteLength);
  1025. lpwdnCur->dTotalLength = lpwdnCur->dDataLength;
  1026. lpwdnCur->dNextWaveDataNode = lpwdn->dNextWaveDataNode;
  1027. lpwdn->dDataLength = dStartOff;
  1028. lpwdn->dTotalLength = dStartOff;
  1029. lpwdn->dNextWaveDataNode = dNewBlockNode;
  1030. }
  1031. dTotalToDelete -= dDeleteLength;
  1032. // old version: if (!lpwdn->dDataLength && dTotalToDelete) {
  1033. if (dTotalToDelete>0) {
  1034. dVirtualWaveDataStart += lpwdn->dDataLength;
  1035. lpwdn = LPWDN(pwd, lpwdn->dNextWaveDataNode);
  1036. dprintf4(("mwDeleteData - more to delete, iterating"));
  1037. }
  1038. }
  1039. /* Step through all nodes. process lpwdnCur, keep lpwdn pointing to the
  1040. previous node (initially NULL)
  1041. */
  1042. pwd->dSize -= ((pwd->dTo - pwd->dFrom) + dTotalToDelete);
  1043. for (lpwdn = NULL, lpwdnCur = LPWDN(pwd, pwd->dWaveDataStartNode);;) {
  1044. if (!lpwdnCur->dDataLength) {
  1045. /* node is empty, so get rid of it */
  1046. if (lpwdn) {
  1047. /* take it out of the middle of the chain */
  1048. if (pwd->dWaveDataCurrentNode == lpwdn->dNextWaveDataNode)
  1049. pwd->dWaveDataCurrentNode = lpwdnCur->dNextWaveDataNode;
  1050. lpwdn->dNextWaveDataNode = lpwdnCur->dNextWaveDataNode;
  1051. } else {
  1052. /* take it out of the start of the chain */
  1053. if (pwd->dWaveDataCurrentNode == pwd->dWaveDataStartNode)
  1054. pwd->dWaveDataCurrentNode = lpwdnCur->dNextWaveDataNode;
  1055. pwd->dWaveDataStartNode = lpwdnCur->dNextWaveDataNode;
  1056. }
  1057. RELEASEBLOCKNODE(lpwdnCur);
  1058. }
  1059. if (lpwdnCur->dNextWaveDataNode == ENDOFNODES){
  1060. break;
  1061. }
  1062. lpwdn = lpwdnCur;
  1063. lpwdnCur = LPWDN(pwd, lpwdn->dNextWaveDataNode);
  1064. }
  1065. if (!pwd->dSize) {
  1066. pwd->dWaveDataStartNode = mwFindAnyFreeDataNode(pwd, 1);
  1067. pwd->dWaveDataCurrentNode = pwd->dWaveDataStartNode;
  1068. lpwdn = LPWDN(pwd, pwd->dWaveDataStartNode);
  1069. lpwdn->dNextWaveDataNode = (DWORD)ENDOFNODES;
  1070. } else if (pwd->dWaveDataCurrentNode == ENDOFNODES) {
  1071. pwd->dVirtualWaveDataStart = 0;
  1072. pwd->dWaveDataCurrentNode = pwd->dWaveDataStartNode;
  1073. for (lpwdn = LPWDN(pwd, pwd->dWaveDataStartNode); pwd->dFrom > pwd->dVirtualWaveDataStart + lpwdn->dDataLength;) {
  1074. pwd->dVirtualWaveDataStart += lpwdn->dDataLength;
  1075. pwd->dWaveDataCurrentNode = lpwdn->dNextWaveDataNode;
  1076. lpwdn = LPWDN(pwd, pwd->dWaveDataCurrentNode);
  1077. }
  1078. }
  1079. }
  1080. /************************************************************************/
  1081. /*
  1082. @doc INTERNAL MCIWAVE
  1083. @func UINT | RecordFile |
  1084. This function is used to Cue or Record wave device input. For normal
  1085. recording mode the function basically queues buffers on the wave
  1086. device, and writes them to a file as they are filled, blocking for
  1087. each buffer. It also makes sure to call <f>mmYield<d> while both
  1088. writing out new buffers, and waiting for buffers to be filled. This
  1089. means that it will try to add all the buffers possible to the input
  1090. wave device, and then write them as fast as possible.
  1091. For Cue mode, the function also tries to add buffers to the wave
  1092. input device, but nothing is ever written out, and only the highest
  1093. level is calculated.
  1094. Within the record loop, the function first checks to see if there
  1095. is a Cue mode buffer waiting, and if so, waits for it. This allows
  1096. only one buffer to be added to the device when in Cue mode. The
  1097. current level is calculated with the contents of the buffer.
  1098. If the function is not in Cue mode, or there is not currently a
  1099. queued buffer, the function tries to add a new buffer to the input
  1100. wave device. This cannot occur if a new command is pending, or there
  1101. are no buffers available. This means that in normal recording mode,
  1102. there will possibly be extra data recorded that does not need to be.
  1103. If an error occurs adding the buffer to the wave device, the record
  1104. function is aborted with an error, else the current outstanding buffer
  1105. count is incremented, and a pointer to the next available recording
  1106. buffer is fetched.
  1107. If no new buffers can be added, the existing buffers are written to
  1108. the file. This section cannot be entered in Cue mode, as it is
  1109. dealt with in the first condition. The task is blocked pending a
  1110. signal from the wave device that a buffer has been filled. It then
  1111. checks to see if any more data needs to be recorded before attempting
  1112. to write that data. Note that all filled buffers are dealt with one
  1113. after the other without yielding or otherwise adding new record
  1114. buffers. If the input capability is much faster than the machine,
  1115. this means that instead of getting a lot of disconnect samples, large
  1116. gaps will be produced. This loop is broken out of when either all the
  1117. buffers that were added are written, or no more buffers are currently
  1118. ready (checks the WHDR_DONE flag).
  1119. If no buffers need to be written, the loop checks for the new command
  1120. flag, which can possibly interrupt or change the current recording.
  1121. The only thing that can really make a difference is a stop command,
  1122. and as this case is handled after all buffers are written, the loop
  1123. can immediately exit.
  1124. The final default condition occurs when all the data has been recorded,
  1125. all the buffers have been released, and no new command was encountered.
  1126. In this case, recording is done, and the record loop is exited.
  1127. @parm <t>PWAVEDESC<d> | pwd |
  1128. Pointer to the wave device descriptor.
  1129. @rdesc Returns the number of outstanding buffers added to the wave device.
  1130. This can be used when removing task signal from the message queue.
  1131. In cases of error, the <e>WAVEDESC.wTaskError<d> flag is set. This
  1132. specific error is not currently returned, as the calling task may not
  1133. have waited for the command to complete. But it is at least used for
  1134. notification in order to determine if Failure status should be sent.
  1135. @xref PlayFile.
  1136. */
  1137. PUBLIC UINT PASCAL FAR RecordFile(
  1138. register PWAVEDESC pwd)
  1139. {
  1140. LPWAVEHDR *lplpWaveHdrRecord;
  1141. LPWAVEHDR *lplpWaveHdrWrite;
  1142. UINT wMode;
  1143. register UINT wBuffersOutstanding;
  1144. if (0 != (pwd->wTaskError = waveInStart(pwd->hWaveIn)))
  1145. return 0;
  1146. for (wBuffersOutstanding = 0, lplpWaveHdrRecord = lplpWaveHdrWrite = pwd->rglpWaveHdr;;) {
  1147. if (ISMODE(pwd, COMMAND_CUE) && wBuffersOutstanding) {
  1148. if (TaskBlock() == WM_USER) {
  1149. wBuffersOutstanding--;
  1150. }
  1151. if (!ISMODE(pwd, COMMAND_NEW)) {
  1152. pwd->dLevel = mwGetLevel(pwd, (*lplpWaveHdrWrite)->lpData, (int)(*lplpWaveHdrWrite)->dwBytesRecorded);
  1153. ADDMODE(pwd, MODE_CUED);
  1154. }
  1155. lplpWaveHdrWrite = NextWaveHdr(pwd, lplpWaveHdrWrite);
  1156. } else if (!ISMODE(pwd, COMMAND_NEW) && (wBuffersOutstanding < pwd->wAudioBuffers)) {
  1157. (*lplpWaveHdrRecord)->dwBufferLength = (wMode & COMMAND_CUE) ? NUM_LEVEL_SAMPLES : min(pwd->dAudioBufferLen, pwd->dTo - pwd->dCur);
  1158. (*lplpWaveHdrRecord)->dwFlags &= ~(WHDR_DONE | WHDR_BEGINLOOP | WHDR_ENDLOOP);
  1159. if (0 != (pwd->wTaskError = waveInAddBuffer(pwd->hWaveIn, *lplpWaveHdrRecord, sizeof(WAVEHDR))))
  1160. break;
  1161. wBuffersOutstanding++;
  1162. lplpWaveHdrRecord = NextWaveHdr(pwd, lplpWaveHdrRecord);
  1163. } else if (wBuffersOutstanding) {
  1164. BOOL fExitRecording;
  1165. for (fExitRecording = FALSE; wBuffersOutstanding && !fExitRecording;) {
  1166. if (TaskBlock() == WM_USER) {
  1167. wBuffersOutstanding--;
  1168. }
  1169. if (pwd->dTo == pwd->dCur) {
  1170. fExitRecording = TRUE;
  1171. break;
  1172. }
  1173. if (!(wMode & COMMAND_CUE))
  1174. if (wMode & MODE_INSERT) {
  1175. if (!mwInsert(pwd, (LPBYTE)(*lplpWaveHdrWrite)->lpData, min((*lplpWaveHdrWrite)->dwBytesRecorded, pwd->dTo - pwd->dCur)))
  1176. fExitRecording = TRUE;
  1177. } else if (!mwOverWrite(pwd, (LPBYTE)(*lplpWaveHdrWrite)->lpData, min((*lplpWaveHdrWrite)->dwBytesRecorded, pwd->dTo - pwd->dCur)))
  1178. fExitRecording = TRUE;
  1179. lplpWaveHdrWrite = NextWaveHdr(pwd, lplpWaveHdrWrite);
  1180. if (!((*lplpWaveHdrWrite)->dwFlags & WHDR_DONE))
  1181. break;
  1182. }
  1183. if (fExitRecording)
  1184. break;
  1185. } else if (!ISMODE(pwd, COMMAND_NEW) || !CheckNewCommand(pwd))
  1186. break;
  1187. else
  1188. wMode = GETMODE(pwd);
  1189. mmYield(pwd);
  1190. }
  1191. REMOVEMODE(pwd, MODE_INSERT | MODE_OVERWRITE);
  1192. return wBuffersOutstanding;
  1193. }
  1194. /************************************************************************/