Source code of Windows XP (NT5)
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.

1712 lines
51 KiB

  1. /* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */
  2. /* edit.c
  3. *
  4. * Editing operations and special effects.
  5. */
  6. /* Revision History.
  7. * 4/ Feb/91 LaurieGr (AKA LKG) Ported to WIN32 / WIN16 common code
  8. * 14/Feb/94 LaurieGr merged Motown and Daytona versions
  9. */
  10. #include "nocrap.h"
  11. #include <windows.h>
  12. #include <windowsx.h>
  13. #include <commdlg.h>
  14. #include <mmsystem.h>
  15. #include <mmreg.h>
  16. #include <string.h>
  17. #define INCLUDE_OLESTUBS
  18. #include "SoundRec.h"
  19. #include "srecids.h"
  20. /* constants */
  21. #define CHVOL_INCDELTAVOLUME 25 // ChangeVolume: % to inc volume by
  22. #define CHVOL_DECDELTAVOLUME 20 // ChangeVolume: % to dec volume by
  23. #define ECHO_VOLUME 25 // AddEcho: % to multiply echo samples
  24. #define ECHO_DELAY 150 // AddEcho: millisec delay for echo
  25. #define WAVEBUFSIZE 400 // IncreasePitch, DecreasePitch
  26. #define FINDWAVE_PICKYNESS 5 // how picky is FindWave?
  27. extern char aszInitFile[]; // soundrec.c
  28. static SZCODE aszSamplesFormat[] = TEXT("%d%c%02d");
  29. static SZCODE aszSamplesNoZeroFormat[] = TEXT("%c%02d");
  30. /* InsertFile(void)
  31. *
  32. * Prompt for the name of a WAVE file to insert at the current position.
  33. */
  34. void FAR PASCAL
  35. InsertFile(BOOL fPaste)
  36. {
  37. TCHAR achFileName[_MAX_PATH]; // name of file to insert
  38. WAVEFORMATEX* pwfInsert=NULL; // WAVE file format of given file
  39. DWORD cb; // size of WAVEFORMATEX
  40. HPBYTE pInsertSamples = NULL; // samples from file to insert
  41. long lInsertSamples; // number of samples in given file
  42. long lSamplesToInsert;// no. samp. at samp. rate of cur. file
  43. TCHAR ach[80]; // buffer for string loading
  44. HCURSOR hcurPrev = NULL; // cursor before hourglass
  45. HPBYTE pchSrc; // pointer into source wave buffer
  46. short * piSrc; // 16-bit pointer
  47. HPBYTE pchDst; // pointer into destination wave buffer
  48. short * piDst; // 16-bit pointer
  49. long lSamplesDst; // bytes to copy into destination buffer
  50. long lDDA; // used to implement DDA algorithm
  51. HMMIO hmmio; // Handle to open file to read from
  52. BOOL fDirty = TRUE; // Is the buffer Dirty?
  53. BOOL fStereoIn;
  54. BOOL fStereoOut;
  55. BOOL fEightIn;
  56. BOOL fEightOut;
  57. BOOL fEditWave = FALSE;
  58. int iTemp;
  59. int iTemp2;
  60. OPENFILENAME ofn;
  61. #ifdef DOWECARE
  62. /* HACK from "server.c" to read objects without CF_WAVE */
  63. extern WORD cfNative;
  64. #endif
  65. if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(gpWaveFormat))
  66. return;
  67. if (fPaste) {
  68. MMIOINFO mmioinfo;
  69. HANDLE h;
  70. BeginWaveEdit();
  71. if (!OpenClipboard(ghwndApp))
  72. return;
  73. LoadString(ghInst, IDS_CLIPBOARD, achFileName, SIZEOF(achFileName));
  74. h = GetClipboardData(CF_WAVE);
  75. #ifdef DOWECARE
  76. if (!h) h = GetClipboardData(cfNative);
  77. #endif
  78. if (h)
  79. {
  80. mmioinfo.fccIOProc = FOURCC_MEM;
  81. mmioinfo.pIOProc = NULL;
  82. mmioinfo.pchBuffer = GlobalLock(h);
  83. mmioinfo.cchBuffer = (long)GlobalSize(h); // initial size
  84. mmioinfo.adwInfo[0] = 0; // grow by this much
  85. hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ);
  86. }
  87. else
  88. {
  89. hmmio = NULL;
  90. }
  91. }
  92. else
  93. {
  94. BOOL f;
  95. achFileName[0] = 0;
  96. /* prompt user for file to open */
  97. LoadString(ghInst, IDS_INSERTFILE, ach, SIZEOF(ach));
  98. ofn.lStructSize = sizeof(OPENFILENAME);
  99. ofn.hwndOwner = ghwndApp;
  100. ofn.hInstance = NULL;
  101. ofn.lpstrFilter = aszFilter;
  102. ofn.lpstrCustomFilter = NULL;
  103. ofn.nMaxCustFilter = 0;
  104. ofn.nFilterIndex = 1;
  105. ofn.lpstrFile = achFileName;
  106. ofn.nMaxFile = SIZEOF(achFileName);
  107. ofn.lpstrFileTitle = NULL;
  108. ofn.nMaxFileTitle = 0;
  109. ofn.lpstrInitialDir = NULL;
  110. ofn.lpstrTitle = ach;
  111. ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  112. ofn.nFileOffset = 0;
  113. ofn.nFileExtension = 0;
  114. ofn.lpstrDefExt = NULL;
  115. ofn.lCustData = 0;
  116. ofn.lpfnHook = NULL;
  117. ofn.lpTemplateName = NULL;
  118. f = GetOpenFileName(&ofn); // get the filename
  119. // did we succeed or not?
  120. if (!f)
  121. goto RETURN_ERROR;
  122. /* read the WAVE file */
  123. hmmio = mmioOpen(achFileName, NULL, MMIO_READ | MMIO_ALLOCBUF);
  124. }
  125. if (hmmio != NULL)
  126. {
  127. MMRESULT mmr;
  128. //
  129. // show hourglass cursor
  130. //
  131. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  132. //
  133. // read the WAVE file
  134. //
  135. mmr = ReadWaveFile( hmmio
  136. , &pwfInsert
  137. , &cb
  138. , &pInsertSamples
  139. , &lInsertSamples
  140. , achFileName
  141. , FALSE );
  142. mmioClose(hmmio, 0);
  143. if (mmr != MMSYSERR_NOERROR)
  144. goto RETURN_ERROR;
  145. if (lInsertSamples == 0)
  146. goto RETURN_SUCCESS;
  147. if (pInsertSamples == NULL)
  148. goto RETURN_ERROR;
  149. if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(pwfInsert))
  150. {
  151. ErrorResBox( ghwndApp
  152. , ghInst
  153. , MB_ICONEXCLAMATION | MB_OK
  154. , IDS_APPTITLE
  155. , fPaste ? IDS_CANTPASTE : IDS_NOTASUPPORTEDFILE
  156. , (LPTSTR) achFileName
  157. );
  158. goto RETURN_ERROR;
  159. }
  160. } else {
  161. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  162. IDS_APPTITLE, IDS_ERROROPEN, (LPTSTR) achFileName);
  163. goto RETURN_ERROR;
  164. }
  165. //jyg:moved
  166. // BeginWaveEdit();
  167. fEditWave = TRUE;
  168. //
  169. // if the current file is empty, treat the insert like a open
  170. //
  171. if (glWaveSamplesValid == 0)
  172. {
  173. DestroyWave();
  174. gpWaveSamples = pInsertSamples;
  175. glWaveSamples = lInsertSamples;
  176. glWaveSamplesValid = lInsertSamples;
  177. gpWaveFormat = pwfInsert;
  178. gcbWaveFormat = cb;
  179. pInsertSamples = NULL;
  180. pwfInsert = NULL;
  181. goto RETURN_SUCCESS;
  182. }
  183. fStereoIn = pwfInsert->nChannels != 1;
  184. fStereoOut = gpWaveFormat->nChannels != 1;
  185. fEightIn = ((LPWAVEFORMATEX)pwfInsert)->wBitsPerSample == 8;
  186. fEightOut = ((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8;
  187. /* figure out how many bytes need to be inserted */
  188. lSamplesToInsert = MulDiv(lInsertSamples, gpWaveFormat->nSamplesPerSec,
  189. pwfInsert->nSamplesPerSec);
  190. #ifdef DEBUG
  191. DPF(TEXT("insert %ld samples, converting from %ld Hz to %ld Hz\n"),
  192. lInsertSamples, pwfInsert->nSamplesPerSec,
  193. gpWaveFormat->nSamplesPerSec);
  194. DPF(TEXT("so %ld samples need to be inserted at position %ld\n"),
  195. lSamplesToInsert, glWavePosition);
  196. #endif
  197. /* reallocate the WAVE buffer to be big enough */
  198. if (!AllocWaveBuffer(glWaveSamplesValid + lSamplesToInsert, TRUE, TRUE))
  199. goto RETURN_ERROR;
  200. glWaveSamplesValid += lSamplesToInsert;
  201. /* create a "gap" in the WAVE buffer to go from this:
  202. * |---glWavePosition---|-rest-of-buffer-|
  203. * to this:
  204. * |---glWavePosition---|----lSamplesToInsert----|-rest-of-buffer-|
  205. * where <glWaveSamplesValid> is the size of the buffer
  206. * *after* reallocation
  207. */
  208. memmove( gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition + lSamplesToInsert)
  209. , gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition)
  210. , wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - (glWavePosition + lSamplesToInsert))
  211. );
  212. /* copy the read-in WAVE file into the "gap" */
  213. pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat,glWavePosition);
  214. piDst = (short *) pchDst;
  215. lSamplesDst = lSamplesToInsert;
  216. pchSrc = pInsertSamples;
  217. piSrc = (short *) pchSrc;
  218. lDDA = -((LONG)gpWaveFormat->nSamplesPerSec);
  219. while (lSamplesDst > 0)
  220. {
  221. /* get a sample, convert to right format */
  222. if (fEightIn) {
  223. iTemp = *((BYTE *) pchSrc);
  224. if (fStereoIn) {
  225. iTemp2 = (unsigned char) *(pchSrc+1);
  226. if (!fStereoOut) {
  227. iTemp = (iTemp + iTemp2) / 2;
  228. }
  229. }
  230. else
  231. iTemp2 = iTemp;
  232. if (!fEightOut) {
  233. iTemp = (iTemp - 128) << 8;
  234. iTemp2 = (iTemp2 - 128) << 8;
  235. }
  236. } else {
  237. iTemp = *piSrc;
  238. if (fStereoIn) {
  239. iTemp2 = *(piSrc+1);
  240. if (!fStereoOut) {
  241. iTemp = (int) ( ( ((long)iTemp) + ((long) iTemp2)
  242. ) / 2);
  243. }
  244. }
  245. else
  246. iTemp2 = iTemp;
  247. if (fEightOut) {
  248. iTemp = (iTemp >> 8) + 128;
  249. iTemp2 = (iTemp2 >> 8) + 128;
  250. }
  251. }
  252. /* Output a sample */
  253. if (fEightOut)
  254. { // Cast on lvalue eliminated -- LKG
  255. *(BYTE *) pchDst = (BYTE) iTemp;
  256. pchDst = (BYTE *)pchDst + 1;
  257. }
  258. else
  259. *piDst++ = (short)iTemp;
  260. if (fStereoOut) {
  261. if (fEightOut)
  262. { // Cast on lvalue eliminated -- LKG
  263. *(BYTE *) pchDst = (BYTE) iTemp2;
  264. pchDst = (BYTE *)pchDst + 1;
  265. }
  266. else
  267. *piDst++ = (short)iTemp2;
  268. }
  269. lSamplesDst--;
  270. /* increment <pchSrc> at the correct rate so that the
  271. * sampling rate of the input file is converted to match
  272. * the sampling rate of the current file
  273. */
  274. lDDA += pwfInsert->nSamplesPerSec;
  275. while (lDDA >= 0) {
  276. lDDA -= gpWaveFormat->nSamplesPerSec;
  277. if (fEightIn)
  278. pchSrc++;
  279. else
  280. piSrc++;
  281. if (fStereoIn) {
  282. if (fEightIn)
  283. pchSrc++;
  284. else
  285. piSrc++;
  286. }
  287. }
  288. }
  289. #ifdef DEBUG
  290. if (!fEightIn)
  291. pchSrc = (HPBYTE) piSrc;
  292. DPF(TEXT("copied %ld bytes from insertion buffer\n"), (long) (pchSrc - pInsertSamples));
  293. #endif
  294. goto RETURN_SUCCESS;
  295. RETURN_ERROR: // do error exit without error message
  296. fDirty = FALSE;
  297. RETURN_SUCCESS: // normal exit
  298. if (fPaste)
  299. CloseClipboard();
  300. if (pInsertSamples != NULL)
  301. GlobalFreePtr(pInsertSamples);
  302. if (pwfInsert != NULL)
  303. GlobalFreePtr(pwfInsert);
  304. if (hcurPrev != NULL)
  305. SetCursor(hcurPrev);
  306. if (fEditWave == TRUE)
  307. EndWaveEdit(fDirty);
  308. /* update the display */
  309. UpdateDisplay(TRUE);
  310. }
  311. /* MixWithFile(void)
  312. *
  313. * Prompt for the name of a WAVE file to mix with the audio starting at
  314. * the current location.
  315. */
  316. void FAR PASCAL
  317. MixWithFile(BOOL fPaste)
  318. {
  319. TCHAR achFileName[_MAX_PATH]; // name of file to mix with
  320. WAVEFORMATEX* pwfMix=NULL; // WAVE file format of given file
  321. UINT cb;
  322. HPBYTE pMixSamples = NULL; // samples from file to mix with
  323. long lMixSamples; // number of samples in given file
  324. long lSamplesToMix; // no. Samples at samp. rate. of cur. file
  325. long lSamplesToAdd; // no. Samples to add in
  326. TCHAR ach[80]; // buffer for string loading
  327. HCURSOR hcurPrev = NULL; // cursor before hourglass
  328. HPBYTE pchSrc; // pointer into source wave buffer
  329. HPBYTE pchDst; // pointer into destination wave buffer
  330. short * piSrc; // pointer into source wave buffer
  331. short * piDst; // pointer into destination wave buffer
  332. long lSamplesDst; // Samples to copy into destination buffer
  333. long lDDA; // used to implement DDA algorithm
  334. int iSample; // value of a waveform sample
  335. long lSample; // value of a waveform sample
  336. HMMIO hmmio;
  337. BOOL fDirty = TRUE;
  338. BOOL fStereoIn;
  339. BOOL fStereoOut;
  340. BOOL fEightIn;
  341. BOOL fEightOut;
  342. BOOL fEditWave = FALSE;
  343. int iTemp;
  344. int iTemp2;
  345. OPENFILENAME ofn;
  346. #ifdef DOWECARE
  347. /* HACK from "server.c" to read objects without CF_WAVE */
  348. extern WORD cfNative;
  349. #endif
  350. if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(gpWaveFormat))
  351. return;
  352. if (fPaste) {
  353. MMIOINFO mmioinfo;
  354. HANDLE h;
  355. BeginWaveEdit();
  356. if (!OpenClipboard(ghwndApp))
  357. return;
  358. LoadString(ghInst, IDS_CLIPBOARD, achFileName, SIZEOF(achFileName));
  359. h = GetClipboardData(CF_WAVE);
  360. #ifdef DOWECARE
  361. if (!h) h = GetClipboardData(cfNative);
  362. #endif
  363. if (h) {
  364. mmioinfo.fccIOProc = FOURCC_MEM;
  365. mmioinfo.pIOProc = NULL;
  366. mmioinfo.pchBuffer = GlobalLock(h);
  367. mmioinfo.cchBuffer = (long)GlobalSize(h); // initial size
  368. mmioinfo.adwInfo[0] = 0; // grow by this much
  369. hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ);
  370. }
  371. else {
  372. hmmio = NULL;
  373. }
  374. }
  375. else {
  376. BOOL f;
  377. achFileName[0] = 0;
  378. /* prompt user for file to open */
  379. LoadString(ghInst, IDS_MIXWITHFILE, ach, SIZEOF(ach));
  380. ofn.lStructSize = sizeof(OPENFILENAME);
  381. ofn.hwndOwner = ghwndApp;
  382. ofn.hInstance = NULL;
  383. ofn.lpstrFilter = aszFilter;
  384. ofn.lpstrCustomFilter = NULL;
  385. ofn.nMaxCustFilter = 0;
  386. ofn.nFilterIndex = 1;
  387. ofn.lpstrFile = achFileName;
  388. ofn.nMaxFile = SIZEOF(achFileName);
  389. ofn.lpstrFileTitle = NULL;
  390. ofn.nMaxFileTitle = 0;
  391. ofn.lpstrInitialDir = NULL;
  392. ofn.lpstrTitle = ach;
  393. ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  394. ofn.nFileOffset = 0;
  395. ofn.nFileExtension = 0;
  396. ofn.lpstrDefExt = NULL;
  397. ofn.lCustData = 0;
  398. ofn.lpfnHook = NULL;
  399. ofn.lpTemplateName = NULL;
  400. f = GetOpenFileName(&ofn); // get the filename for mixing
  401. // see if we continue
  402. if (!f)
  403. goto RETURN_ERROR;
  404. /* read the WAVE file */
  405. hmmio = mmioOpen(achFileName, NULL, MMIO_READ | MMIO_ALLOCBUF);
  406. }
  407. if (hmmio != NULL)
  408. {
  409. MMRESULT mmr;
  410. //
  411. // show hourglass cursor
  412. //
  413. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  414. //
  415. // read the WAVE file
  416. //
  417. mmr = ReadWaveFile( hmmio
  418. , &pwfMix // wave format
  419. , &cb // wave format size
  420. , &pMixSamples // samples
  421. , &lMixSamples // number of samples
  422. , achFileName // file name for error
  423. , FALSE ); // cache riff?
  424. mmioClose(hmmio, 0);
  425. if (mmr != MMSYSERR_NOERROR)
  426. goto RETURN_ERROR;
  427. if (lMixSamples == 0)
  428. goto RETURN_SUCCESS;
  429. if (pMixSamples == NULL)
  430. goto RETURN_ERROR;
  431. if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(pwfMix)) {
  432. ErrorResBox( ghwndApp
  433. , ghInst
  434. , MB_ICONEXCLAMATION | MB_OK
  435. , IDS_APPTITLE
  436. , fPaste ? IDS_CANTPASTE : IDS_NOTASUPPORTEDFILE
  437. , (LPTSTR) achFileName
  438. );
  439. goto RETURN_ERROR;
  440. }
  441. }
  442. else
  443. {
  444. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  445. IDS_APPTITLE, IDS_ERROROPEN, (LPTSTR) achFileName);
  446. goto RETURN_ERROR;
  447. }
  448. //jyg: moved
  449. // BeginWaveEdit();
  450. fEditWave = TRUE;
  451. //
  452. // if the current file is empty, treat the insert like a open
  453. //
  454. if (glWaveSamplesValid == 0)
  455. {
  456. DestroyWave();
  457. gpWaveSamples = pMixSamples;
  458. glWaveSamples = lMixSamples;
  459. glWaveSamplesValid = lMixSamples;
  460. gpWaveFormat = pwfMix;
  461. gcbWaveFormat = cb;
  462. pMixSamples = NULL;
  463. pwfMix = NULL;
  464. goto RETURN_SUCCESS;
  465. }
  466. fStereoIn = pwfMix->nChannels != 1;
  467. fStereoOut = gpWaveFormat->nChannels != 1;
  468. fEightIn = ((LPWAVEFORMATEX)pwfMix)->wBitsPerSample == 8;
  469. fEightOut = ((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8;
  470. /* figure out how many Samples need to be mixed in */
  471. lSamplesToMix = MulDiv(lMixSamples, gpWaveFormat->nSamplesPerSec,
  472. pwfMix->nSamplesPerSec);
  473. lSamplesToAdd = lSamplesToMix - (glWaveSamplesValid - glWavePosition);
  474. if (lSamplesToAdd < 0)
  475. lSamplesToAdd = 0;
  476. #ifdef DEBUG
  477. DPF(TEXT("mix in %ld samples, converting from %ld Hz to %ld Hz\n"),
  478. lMixSamples, pwfMix->nSamplesPerSec,
  479. gpWaveFormat->nSamplesPerSec);
  480. DPF(TEXT("so %ld Samples need to be mixed in at position %ld (add %ld)\n"),
  481. lSamplesToMix, glWavePosition, lSamplesToAdd);
  482. #endif
  483. if (lSamplesToAdd > 0) {
  484. /* mixing the specified file at the current location will
  485. * require the current file's wave buffer to be expanded
  486. * by <lSamplesToAdd>
  487. */
  488. /* reallocate the WAVE buffer to be big enough */
  489. if (!AllocWaveBuffer(glWaveSamplesValid + lSamplesToAdd,TRUE, TRUE))
  490. goto RETURN_ERROR;
  491. /* fill in the new part of the buffer with silence
  492. */
  493. lSamplesDst = lSamplesToAdd;
  494. /* If stereo, just twice as many samples
  495. */
  496. if (fStereoOut)
  497. lSamplesDst *= 2;
  498. pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat,glWaveSamplesValid);
  499. if (fEightOut) {
  500. while (lSamplesDst-- > 0) {
  501. // cast on lvalue eliminated
  502. *((BYTE *) pchDst) = 128;
  503. pchDst = (BYTE *)pchDst + 1;
  504. }
  505. }
  506. else {
  507. piDst = (short *) pchDst;
  508. while (lSamplesDst-- > 0) {
  509. *((short *) piDst) = 0;
  510. piDst = (short *)piDst + 1;
  511. }
  512. }
  513. glWaveSamplesValid += lSamplesToAdd;
  514. }
  515. /* mix the read-in WAVE file with the current file starting at the
  516. * current position
  517. */
  518. pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition);
  519. piDst = (short *) pchDst;
  520. lSamplesDst = lSamplesToMix;
  521. pchSrc = pMixSamples;
  522. piSrc = (short *) pchSrc;
  523. lDDA = -((LONG)gpWaveFormat->nSamplesPerSec);
  524. while (lSamplesDst > 0)
  525. {
  526. /* get a sample, convert to right format */
  527. if (fEightIn) {
  528. iTemp = (int) (unsigned char) *pchSrc;
  529. if (fStereoIn) {
  530. iTemp2 = (int) (unsigned char) *(pchSrc+1);
  531. if (!fStereoOut) {
  532. iTemp = (iTemp + iTemp2) / 2;
  533. }
  534. } else
  535. iTemp2 = iTemp;
  536. if (!fEightOut) {
  537. iTemp = (iTemp - 128) << 8;
  538. iTemp2 = (iTemp2 - 128) << 8;
  539. }
  540. } else {
  541. iTemp = *piSrc;
  542. if (fStereoIn) {
  543. iTemp2 = *(piSrc+1);
  544. if (!fStereoOut) {
  545. iTemp = (int) ((((long) iTemp)
  546. + ((long) iTemp2)) / 2);
  547. }
  548. } else
  549. iTemp2 = iTemp;
  550. if (fEightOut) {
  551. iTemp = (iTemp >> 8) + 128;
  552. iTemp2 = (iTemp2 >> 8) + 128;
  553. }
  554. }
  555. /* Output a sample */
  556. if (fEightOut)
  557. {
  558. iSample = (int) *((BYTE *) pchDst)
  559. + iTemp - 128;
  560. *((BYTE *) pchDst++) = (BYTE)
  561. (iSample < 0 ? 0 :
  562. (iSample > 255 ? 255 : iSample));
  563. }
  564. else
  565. {
  566. lSample = (long) *((short *) piDst)
  567. + (long) iTemp;
  568. *((short *) piDst++) = (int)
  569. (lSample < -32768L
  570. ? -32768 : (lSample > 32767L
  571. ? 32767 : (short) lSample));
  572. }
  573. if (fStereoOut) {
  574. if (fEightOut)
  575. {
  576. iSample = (int) *((BYTE *) pchDst)
  577. + iTemp2 - 128;
  578. *((BYTE *) pchDst++) = (BYTE)
  579. (iSample < 0
  580. ? 0 : (iSample > 255
  581. ? 255 : iSample));
  582. }
  583. else
  584. {
  585. lSample = (long) *((short *) piDst)
  586. + (long) iTemp2;
  587. *((short *) piDst++) = (short)
  588. (lSample < -32768L
  589. ? -32768 : (lSample > 32767L
  590. ? 32767 : (short) lSample));
  591. }
  592. }
  593. lSamplesDst--;
  594. /* increment <pchSrc> at the correct rate so that the
  595. * sampling rate of the input file is converted to match
  596. * the sampling rate of the current file
  597. */
  598. lDDA += pwfMix->nSamplesPerSec;
  599. while (lDDA >= 0)
  600. {
  601. lDDA -= gpWaveFormat->nSamplesPerSec;
  602. if (fEightIn)
  603. pchSrc++;
  604. else
  605. piSrc++;
  606. if (fStereoIn) {
  607. if (fEightIn)
  608. pchSrc++;
  609. else
  610. piSrc++;
  611. }
  612. }
  613. }
  614. #ifdef DEBUG
  615. if (!fEightIn)
  616. pchSrc = (HPBYTE) piSrc;
  617. DPF(TEXT("copied %ld bytes from mix buffer\n"),
  618. (long) (pchSrc - pMixSamples));
  619. #endif
  620. goto RETURN_SUCCESS;
  621. RETURN_ERROR: // do error exit without error message
  622. fDirty = FALSE;
  623. RETURN_SUCCESS: // normal exit
  624. if (fPaste)
  625. CloseClipboard();
  626. if (pMixSamples != NULL)
  627. GlobalFreePtr(pMixSamples);
  628. if (pwfMix != NULL)
  629. GlobalFreePtr(pwfMix);
  630. if (hcurPrev != NULL)
  631. SetCursor(hcurPrev);
  632. if (fEditWave == TRUE)
  633. EndWaveEdit(fDirty);
  634. /* update the display */
  635. UpdateDisplay(TRUE);
  636. }
  637. /* DeleteBefore()
  638. *
  639. * Delete samples before <glWavePosition>.
  640. */
  641. void FAR PASCAL
  642. DeleteBefore(void)
  643. {
  644. TCHAR ach[40];
  645. long lTime;
  646. int id;
  647. if (glWavePosition == 0) // nothing to do?
  648. return; // don't set dirty flag
  649. BeginWaveEdit();
  650. /* jyg - made this conditional because of rounding errors at
  651. * the end of buffer case
  652. */
  653. if (glWavePosition != glWaveSamplesValid)
  654. glWavePosition = wfSamplesToSamples(gpWaveFormat, glWavePosition);
  655. /* get the current wave position */
  656. lTime = wfSamplesToTime(gpWaveFormat, glWavePosition);
  657. if (gfLZero || ((int)(lTime/1000) != 0)) // ??? what are these casts ???
  658. wsprintf(ach, aszSamplesFormat, (int)(lTime/1000), chDecimal, (int)((lTime/10)%100));
  659. else
  660. wsprintf(ach, aszSamplesNoZeroFormat, chDecimal, (int)((lTime/10)%100));
  661. /* prompt user for permission */
  662. id = ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OKCANCEL,
  663. IDS_APPTITLE, IDS_DELBEFOREWARN, (LPTSTR) ach);
  664. if (id != IDOK)
  665. return;
  666. /* copy the samples after <glWavePosition> to the beginning of
  667. * the buffer
  668. */
  669. memmove(gpWaveSamples,
  670. gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition),
  671. wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - glWavePosition));
  672. /* reallocate the buffer to be <glWavePosition> samples smaller */
  673. AllocWaveBuffer(glWaveSamplesValid - glWavePosition, TRUE, TRUE);
  674. glWavePosition = 0L;
  675. EndWaveEdit(TRUE);
  676. /* update the display */
  677. UpdateDisplay(TRUE);
  678. } /* DeleteBefore */
  679. /* DeleteAfter()
  680. *
  681. * Delete samples after <glWavePosition>.
  682. */
  683. void FAR PASCAL
  684. DeleteAfter(void)
  685. {
  686. TCHAR ach[40];
  687. long lTime;
  688. int id;
  689. if (glWavePosition == glWaveSamplesValid) // nothing to do?
  690. return; // don't set dirty flag
  691. glWavePosition = wfSamplesToSamples(gpWaveFormat, glWavePosition);
  692. BeginWaveEdit();
  693. /* get the current wave position */
  694. lTime = wfSamplesToTime(gpWaveFormat, glWavePosition);
  695. if (gfLZero || ((int)(lTime/1000) != 0)) // ??? casts ???
  696. wsprintf(ach, aszSamplesFormat, (int)(lTime/1000), chDecimal, (int)((lTime/10)%100));
  697. else
  698. wsprintf(ach, aszSamplesNoZeroFormat, chDecimal, (int)((lTime/10)%100));
  699. /* prompt user for permission */
  700. id = ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OKCANCEL,
  701. IDS_APPTITLE, IDS_DELAFTERWARN, (LPTSTR) ach);
  702. if (id != IDOK)
  703. return;
  704. /* reallocate the buffer to be <glWavePosition> samples in size */
  705. AllocWaveBuffer(glWavePosition, TRUE, TRUE);
  706. EndWaveEdit(TRUE);
  707. /* update the display */
  708. UpdateDisplay(TRUE);
  709. } /* DeleteAfter */
  710. /* ChangeVolume(fIncrease)
  711. *
  712. * Increase the volume (if <fIncrease> is TRUE) or decrease the volume
  713. * (if <fIncrease> is FALSE) of samples in the wave buffer by CHVOL_DELTAVOLUME
  714. * percent.
  715. */
  716. void FAR PASCAL
  717. ChangeVolume(BOOL fIncrease)
  718. {
  719. HPBYTE pch = gpWaveSamples; // ptr. into waveform buffer
  720. long lSamples; // samples to modify
  721. HCURSOR hcurPrev = NULL; // cursor before hourglass
  722. int iFactor; // amount to multiply amplitude by
  723. short * pi = (short *) gpWaveSamples;
  724. if (glWaveSamplesValid == 0L) // nothing to do?
  725. return; // don't set dirty flag
  726. if (!IsWaveFormatPCM(gpWaveFormat))
  727. return;
  728. /* show hourglass cursor */
  729. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  730. BeginWaveEdit();
  731. /* for stereo, just twice as many samples */
  732. lSamples = glWaveSamplesValid * gpWaveFormat->nChannels;
  733. iFactor = 100 + (fIncrease ? CHVOL_INCDELTAVOLUME : -CHVOL_DECDELTAVOLUME);
  734. if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8) {
  735. /* 8-bit: samples 0-255 */
  736. int iTemp;
  737. while (lSamples-- > 0)
  738. {
  739. iTemp = ( ((short) *((BYTE *) pch) - 128)
  740. * iFactor
  741. )
  742. / 100 + 128;
  743. *((BYTE *) pch++) = (BYTE)
  744. (iTemp < 0 ? 0 : (iTemp > 255 ? 255 : iTemp));
  745. }
  746. } else {
  747. /* 16-bit: samples -32768 - 32767 */
  748. long lTemp;
  749. while (lSamples-- > 0)
  750. {
  751. lTemp = (((long) *pi) * iFactor) / 100;
  752. *(pi++) = (short) (lTemp < -32768L ? -32768 :
  753. (lTemp > 32767L ?
  754. 32767 : (short) lTemp));
  755. }
  756. }
  757. EndWaveEdit(TRUE);
  758. if (hcurPrev != NULL)
  759. SetCursor(hcurPrev);
  760. /* update the display */
  761. UpdateDisplay(TRUE);
  762. }
  763. /* MakeFaster()
  764. *
  765. * Make the sound play twice as fast.
  766. */
  767. void FAR PASCAL
  768. MakeFaster(void)
  769. {
  770. HPBYTE pchSrc; // pointer into source part of buffer
  771. HPBYTE pchDst; // pointer into destination part
  772. short * piSrc;
  773. short * piDst;
  774. long lSamplesDst; // samples to copy into destination buffer
  775. HCURSOR hcurPrev = NULL; // cursor before hourglass
  776. if (glWaveSamplesValid == 0L) // nothing to do?
  777. return; // don't set dirty flag
  778. if (!IsWaveFormatPCM(gpWaveFormat))
  779. return;
  780. /* show hourglass cursor */
  781. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  782. BeginWaveEdit();
  783. /* move the current position so it will correspond to the same point
  784. * in the audio before and after the change-pitch operation
  785. */
  786. glWavePosition /= 2L;
  787. /* delete every other sample */
  788. lSamplesDst = glWaveSamplesValid / 2L;
  789. if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8) {
  790. pchSrc = pchDst = gpWaveSamples;
  791. if (gpWaveFormat->nChannels == 1) {
  792. while (lSamplesDst-- > 0)
  793. {
  794. *pchDst++ = *pchSrc++;
  795. pchSrc++;
  796. }
  797. } else {
  798. while (lSamplesDst-- > 0)
  799. {
  800. *pchDst++ = *pchSrc++;
  801. *pchDst++ = *pchSrc++;
  802. pchSrc++;
  803. pchSrc++;
  804. }
  805. }
  806. } else {
  807. piSrc = piDst = (short *) gpWaveSamples;
  808. if (gpWaveFormat->nChannels == 1) {
  809. while (lSamplesDst-- > 0)
  810. {
  811. *piDst++ = *piSrc++;
  812. piSrc++;
  813. }
  814. } else {
  815. while (lSamplesDst-- > 0)
  816. {
  817. *piDst++ = *piSrc++;
  818. *piDst++ = *piSrc++;
  819. piSrc++;
  820. piSrc++;
  821. }
  822. }
  823. }
  824. /* reallocate the WAVE buffer to be half as big enough */
  825. //!!WinEval(AllocWaveBuffer(glWaveSamplesValid / 2L));
  826. AllocWaveBuffer(glWaveSamplesValid / 2L, TRUE, TRUE);
  827. EndWaveEdit(TRUE);
  828. if (hcurPrev != NULL)
  829. SetCursor(hcurPrev);
  830. /* update the display */
  831. UpdateDisplay(TRUE);
  832. }
  833. /* MakeSlower()
  834. *
  835. * Make the sound play twice as slow.
  836. */
  837. void FAR PASCAL
  838. MakeSlower(void)
  839. {
  840. HPBYTE pchSrc; // pointer into source part of buffer
  841. HPBYTE pchDst; // pointer into destination part
  842. short * piSrc;
  843. short * piDst;
  844. long lSamplesSrc; // samples to copy from source buffer
  845. HCURSOR hcurPrev = NULL; // cursor before hourglass
  846. long lPrevPosition; // previous "current position"
  847. int iSample; // current source sample
  848. int iPrevSample; // previous sample (for interpolation)
  849. int iSample2;
  850. int iPrevSample2;
  851. long lSample;
  852. long lPrevSample;
  853. long lSample2;
  854. long lPrevSample2;
  855. if (glWaveSamplesValid == 0L) // nothing to do?
  856. return; // don't set dirty flag
  857. if (!IsWaveFormatPCM(gpWaveFormat))
  858. return;
  859. /* show hourglass cursor */
  860. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  861. BeginWaveEdit();
  862. /* reallocate the WAVE buffer to be twice as big */
  863. lPrevPosition = glWavePosition;
  864. if (!AllocWaveBuffer(glWaveSamplesValid * 2L, TRUE, TRUE))
  865. goto RETURN;
  866. /* each source sample generates two destination samples;
  867. * use interpolation to generate new samples; must go backwards
  868. * through the buffer to avoid destroying data
  869. */
  870. pchSrc = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
  871. pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid * 2L);
  872. lSamplesSrc = glWaveSamplesValid;
  873. if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8)
  874. {
  875. if (gpWaveFormat->nChannels == 1)
  876. {
  877. iPrevSample = *((BYTE *) (pchSrc - 1));
  878. while (lSamplesSrc-- > 0)
  879. {
  880. pchSrc = ((BYTE *) pchSrc) - 1;
  881. iSample = *((BYTE *) pchSrc);
  882. *--pchDst = (BYTE)((iSample + iPrevSample)/2);
  883. *--pchDst = (BYTE) iSample;
  884. iPrevSample = iSample;
  885. }
  886. }
  887. else
  888. {
  889. iPrevSample = *((BYTE *) (pchSrc - 2));
  890. iPrevSample2 = *((BYTE *) (pchSrc - 1));
  891. while (lSamplesSrc-- > 0)
  892. {
  893. pchSrc = ((BYTE *) pchSrc)-1;
  894. iSample2 = *((BYTE *) pchSrc);
  895. pchSrc = ((BYTE *) pchSrc)-1;
  896. iSample = *((BYTE *) pchSrc);
  897. *--pchDst = (BYTE)((iSample2 + iPrevSample2)
  898. / 2);
  899. *--pchDst = (BYTE)((iSample + iPrevSample)
  900. / 2);
  901. *--pchDst = (BYTE) iSample2;
  902. *--pchDst = (BYTE) iSample;
  903. iPrevSample = iSample;
  904. iPrevSample2 = iSample2;
  905. }
  906. }
  907. }
  908. else
  909. {
  910. piDst = (short *) pchDst;
  911. piSrc = (short *) pchSrc;
  912. if (gpWaveFormat->nChannels == 1)
  913. {
  914. lPrevSample = *(piSrc - 1);
  915. while (lSamplesSrc-- > 0)
  916. {
  917. lSample = *--piSrc;
  918. *--piDst = (short)((lSample + lPrevSample)/2);
  919. *--piDst = (short) lSample;
  920. lPrevSample = lSample;
  921. }
  922. }
  923. else
  924. {
  925. lPrevSample = *(piSrc - 2);
  926. lPrevSample2 = *(piSrc - 1);
  927. while (lSamplesSrc-- > 0)
  928. {
  929. lSample2 = *--piSrc;
  930. lSample = *--piSrc;
  931. *--piDst = (short)((lSample2 + lPrevSample2)/2);
  932. *--piDst = (short)((lSample + lPrevSample) / 2);
  933. *--piDst = (short) lSample2;
  934. *--piDst = (short) lSample;
  935. lPrevSample = lSample;
  936. lPrevSample2 = lSample2;
  937. }
  938. }
  939. }
  940. /* the entire buffer now contains valid samples */
  941. glWaveSamplesValid *= 2L;
  942. /* move the current position so it will correspond to the same point
  943. * in the audio before and after the change-pitch operation
  944. */
  945. glWavePosition = lPrevPosition * 2L;
  946. //!!WinAssert(glWavePosition <= glWaveSamplesValid);
  947. RETURN:
  948. EndWaveEdit(TRUE);
  949. if (hcurPrev != NULL)
  950. SetCursor(hcurPrev);
  951. /* update the display */
  952. UpdateDisplay(TRUE);
  953. }
  954. #if 0
  955. /* pchNew = FindWave(pch, pchEnd, ppchWaveBuf)
  956. *
  957. * Assuming <pch> points within the wave buffer and <pchEnd> points past the
  958. * end of the buffer, find the beginning of the next "wave", i.e. the point
  959. * where the waveform starts rising (after it has fallen).
  960. *
  961. * <ppchWaveBuf> points to a pointer that points to a buffer that is filled
  962. * in with a copy of the wave. The pointer <*ppchWaveBuf> is modified and
  963. * upon return will point past the end of the wave.
  964. */
  965. HPBYTE NEAR PASCAL
  966. FindWave(HPBYTE pch, HPBYTE pchEnd, NPBYTE *ppchWaveBuf)
  967. {
  968. BYTE bLowest = 255;
  969. BYTE bHighest = 0;
  970. BYTE bLowPoint;
  971. BYTE bHighPoint;
  972. BYTE bDelta;
  973. HPBYTE pchWalk;
  974. BYTE b;
  975. #ifdef VERBOSEDEBUG
  976. NPBYTE pchWaveBufInit = *ppchWaveBuf;
  977. #endif
  978. if (pch == pchEnd)
  979. return pch;
  980. for (pchWalk = pch; pchWalk != pchEnd; pchWalk++)
  981. {
  982. b = *pchWalk;
  983. b = *((BYTE *) pchWalk);
  984. if (bLowest > b)
  985. bLowest = b;
  986. if (bHighest < b)
  987. bHighest = b;
  988. }
  989. bDelta = (bHighest - bLowest) / FINDWAVE_PICKYNESS;
  990. bLowPoint = bLowest + bDelta;
  991. bHighPoint = bHighest - bDelta;
  992. //!!WinAssert(bLowPoint >= bLowest);
  993. //!!WinAssert(bHighPoint <= bHighest);
  994. #ifdef VERBOSEDEBUG
  995. DPF(TEXT("0x%08lX: %3d to %3d"), (DWORD) pch,
  996. (int) bLowPoint, (int) bHighPoint);
  997. #endif
  998. if (bLowPoint == bHighPoint)
  999. {
  1000. /* avoid infinite loop */
  1001. *(*ppchWaveBuf)++ = *((BYTE *) pch++);
  1002. #ifdef VERBOSEDEBUG
  1003. DPF(TEXT(" (equal)\n"));
  1004. #endif
  1005. return pch;
  1006. }
  1007. /* find a "peak" */
  1008. while ((pch != pchEnd) && (*((BYTE *) pch) < bHighPoint))
  1009. *(*ppchWaveBuf)++ = *((BYTE *) pch++);
  1010. /* find a "valley" */
  1011. while ((pch != pchEnd) && (*((BYTE *) pch) > bLowPoint))
  1012. *(*ppchWaveBuf)++ = *((BYTE *) pch++);
  1013. #ifdef VERBOSEDEBUG
  1014. DPF(TEXT(" (copied %d)\n"), *ppchWaveBuf - pchWaveBufInit);
  1015. #endif
  1016. return pch;
  1017. }
  1018. #endif
  1019. #if 0
  1020. /* IncreasePitch()
  1021. *
  1022. * Increase the pitch of samples in the wave buffer by one octave.
  1023. */
  1024. void FAR PASCAL
  1025. IncreasePitch(void)
  1026. {
  1027. HCURSOR hcurPrev = NULL; // cursor before hourglass
  1028. HPBYTE pchEndFile; // end of file's buffer
  1029. HPBYTE pchStartWave; // start of one wave
  1030. HPBYTE pchMaxWave; // last place where wave may end
  1031. HPBYTE pchEndWave; // end an actual wave
  1032. char achWaveBuf[WAVEBUFSIZE];
  1033. NPBYTE pchWaveBuf;
  1034. NPBYTE pchSrc;
  1035. HPBYTE pchDst;
  1036. if (glWaveSamplesValid == 0L) // nothing to do?
  1037. return; // don't set dirty flag
  1038. if (!IsWaveFormatPCM(gpWaveFormat))
  1039. return;
  1040. /* show hourglass cursor */
  1041. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1042. BeginWaveEdit();
  1043. /* find each wave in the wave buffer and double it */
  1044. pchEndFile = gpWaveSamples + glWaveSamplesValid;
  1045. pchStartWave = gpWaveSamples;
  1046. while (TRUE)
  1047. {
  1048. pchMaxWave = pchStartWave + WAVEBUFSIZE;
  1049. if (pchMaxWave > pchEndFile)
  1050. pchMaxWave = pchEndFile;
  1051. pchWaveBuf = achWaveBuf;
  1052. pchEndWave = FindWave(pchStartWave, pchMaxWave, &pchWaveBuf);
  1053. pchSrc = achWaveBuf;
  1054. pchDst = pchStartWave;
  1055. if (pchSrc == pchWaveBuf)
  1056. break; // no samples copied
  1057. while (pchDst != pchEndWave)
  1058. {
  1059. *pchDst++ = *pchSrc++;
  1060. pchSrc++;
  1061. if (pchSrc >= pchWaveBuf)
  1062. {
  1063. if (pchSrc == pchWaveBuf)
  1064. pchSrc = achWaveBuf;
  1065. else
  1066. pchSrc = achWaveBuf + 1;
  1067. }
  1068. }
  1069. pchStartWave = pchEndWave;
  1070. }
  1071. EndWaveEdit(TRUE);
  1072. if (hcurPrev != NULL)
  1073. SetCursor(hcurPrev);
  1074. /* update the display */
  1075. UpdateDisplay(TRUE);
  1076. }
  1077. #endif
  1078. #if 0
  1079. /* DecreasePitch()
  1080. *
  1081. * Decrease the pitch of samples in the wave buffer by one octave.
  1082. */
  1083. void FAR PASCAL
  1084. DecreasePitch(void)
  1085. {
  1086. HCURSOR hcurPrev = NULL; // cursor before hourglass
  1087. HPBYTE pchEndFile; // end of file's buffer
  1088. HPBYTE pchStartWave; // start of one wave
  1089. HPBYTE pchMaxWave; // last place where wave may end
  1090. HPBYTE pchEndWave; // end an actual wave
  1091. char achWaveBuf[WAVEBUFSIZE];
  1092. NPBYTE pchWaveBuf; // end of first wave in <achWaveBuf>
  1093. NPBYTE pchSrc; // place to read samples from
  1094. NPBYTE pchSrcEnd; // end of place to read samples from
  1095. int iSample; // current source sample
  1096. int iPrevSample; // previous sample (for interpolation)
  1097. HPBYTE pchDst; // where result gets put in buffer
  1098. long lNewFileSize; // file size after pitch change
  1099. if (glWaveSamplesValid == 0L) // nothing to do?
  1100. return; // don't set dirty flag
  1101. if (!IsWaveFormatPCM(gpWaveFormat))
  1102. return;
  1103. /* show hourglass cursor */
  1104. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1105. BeginWaveEdit();
  1106. /* find each pair of waves in the wave buffer, discard the longer
  1107. * of the two waves, and expand the shorter of the two waves to
  1108. * twice its size
  1109. */
  1110. pchEndFile = gpWaveSamples + glWaveSamplesValid;
  1111. pchStartWave = gpWaveSamples; // read waves from here
  1112. pchDst = gpWaveSamples; // write waves to here
  1113. while (TRUE)
  1114. {
  1115. pchMaxWave = pchStartWave + WAVEBUFSIZE;
  1116. if (pchMaxWave > pchEndFile)
  1117. pchMaxWave = pchEndFile;
  1118. /* read one wave -- make <pchWaveBuf> point to the end
  1119. * of the wave that's copied into <achWaveBuf>
  1120. */
  1121. pchWaveBuf = achWaveBuf;
  1122. pchEndWave = FindWave(pchStartWave, pchMaxWave, &pchWaveBuf);
  1123. if (pchWaveBuf == achWaveBuf)
  1124. break;
  1125. /* read another wave -- make <pchWaveBuf> now point to the end
  1126. * of that wave that's copied into <achWaveBuf>
  1127. */
  1128. pchEndWave = FindWave(pchEndWave, pchMaxWave, &pchWaveBuf);
  1129. pchSrc = achWaveBuf;
  1130. pchSrcEnd = achWaveBuf + ((pchWaveBuf - achWaveBuf) / 2);
  1131. iPrevSample = *((BYTE *) pchSrc);
  1132. while (pchSrc != pchSrcEnd)
  1133. {
  1134. iSample = *((BYTE *) pchSrc)++;
  1135. *pchDst++ = (BYTE) ((iSample + iPrevSample) / 2);
  1136. *pchDst++ = iSample;
  1137. iPrevSample = iSample;
  1138. }
  1139. pchStartWave = pchEndWave;
  1140. }
  1141. /* file may have shrunk */
  1142. lNewFileSize = pchDst - gpWaveSamples;
  1143. //!!WinAssert(lNewFileSize <= glWaveSamplesValid);
  1144. #ifdef DEBUG
  1145. DPF(TEXT("old file size is %ld, new size is %ld\n"),
  1146. glWaveSamplesValid, lNewFileSize);
  1147. #endif
  1148. AllocWaveBuffer(lNewFileSize, TRUE, TRUE);
  1149. EndWaveEdit(TRUE);
  1150. if (hcurPrev != NULL)
  1151. SetCursor(hcurPrev);
  1152. /* update the display */
  1153. UpdateDisplay(TRUE);
  1154. }
  1155. #endif
  1156. /* AddEcho()
  1157. *
  1158. * Add echo to samples in the wave buffer.
  1159. */
  1160. void FAR PASCAL
  1161. AddEcho(void)
  1162. {
  1163. HCURSOR hcurPrev = NULL; // cursor before hourglass
  1164. long lDeltaSamples; // no. samples for echo delay
  1165. long lSamples; // no. samples to modify
  1166. int iAmpSrc; // current source sample amplitude
  1167. int iAmpDst; // current destination sample amplitude
  1168. if (!IsWaveFormatPCM(gpWaveFormat))
  1169. return;
  1170. BeginWaveEdit();
  1171. /* figure out how many samples need to be modified */
  1172. lDeltaSamples = MulDiv((long) ECHO_DELAY,
  1173. gpWaveFormat->nSamplesPerSec, 1000L);
  1174. /* Set lSamples to be number of samples * number of channels */
  1175. lSamples = (glWaveSamplesValid - lDeltaSamples)
  1176. * gpWaveFormat->nChannels;
  1177. if (lSamples <= 0L) // nothing to do?
  1178. return; // don't set dirty flag
  1179. /* show hourglass cursor */
  1180. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1181. /* copy ECHO_VOLUME percent of each source sample (starting at
  1182. * ECHO_DELAY milliseconds from the end of the the buffer)
  1183. * to the each destination sample (starting at the end of the
  1184. * buffer)
  1185. */
  1186. if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8)
  1187. {
  1188. HPBYTE pchSrc; // pointer into source part of buffer
  1189. HPBYTE pchDst; // pointer into destination part
  1190. int iSample; // destination sample
  1191. pchSrc = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - lDeltaSamples);
  1192. pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
  1193. while (lSamples-- > 0)
  1194. {
  1195. pchSrc = ((BYTE *) pchSrc) - 1;
  1196. iAmpSrc = (int) *((BYTE *) pchSrc) - 128;
  1197. pchDst = ((BYTE *) pchDst) - 1;
  1198. iAmpDst = (int) *((BYTE *) pchDst) - 128;
  1199. iSample = iAmpDst + (iAmpSrc * ECHO_VOLUME) / 100
  1200. + 128;
  1201. *((BYTE *) pchDst) = (BYTE)
  1202. (iSample < 0 ? 0 : (iSample > 255
  1203. ? 255 : iSample));
  1204. }
  1205. }
  1206. else
  1207. {
  1208. short * piSrc; // pointer into source part of buffer
  1209. short * piDst; // pointer into destination part
  1210. long lSample;// destination sample
  1211. piSrc = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - lDeltaSamples));
  1212. piDst = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid));
  1213. while (lSamples-- > 0)
  1214. {
  1215. iAmpSrc = *--piSrc;
  1216. iAmpDst = *--piDst;
  1217. lSample = ((long) iAmpSrc * ECHO_VOLUME) / 100 + (long) iAmpDst;
  1218. *piDst = (short) (lSample < -32768L
  1219. ? -32768 : (lSample > 32767L
  1220. ? 32767 : (short) lSample));
  1221. }
  1222. }
  1223. EndWaveEdit(TRUE);
  1224. if (hcurPrev != NULL)
  1225. SetCursor(hcurPrev);
  1226. /* update the display */
  1227. UpdateDisplay(TRUE);
  1228. }
  1229. /* Reverse()
  1230. *
  1231. * Reverse samples in the wave buffer.
  1232. */
  1233. void FAR PASCAL
  1234. Reverse(void)
  1235. {
  1236. HCURSOR hcurPrev = NULL; // cursor before hourglass
  1237. HPBYTE pchA, pchB; // pointers into buffer
  1238. short * piA;
  1239. short * piB;
  1240. long lSamples; // no. Samples to modify
  1241. char chTmp; // for swapping
  1242. int iTmp;
  1243. if (glWaveSamplesValid == 0L) // nothing to do?
  1244. return; // don't set dirty flag
  1245. if (!IsWaveFormatPCM(gpWaveFormat))
  1246. return;
  1247. BeginWaveEdit();
  1248. /* show hourglass cursor */
  1249. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1250. lSamples = glWaveSamplesValid / 2;
  1251. if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8)
  1252. {
  1253. pchA = gpWaveSamples;
  1254. if (gpWaveFormat->nChannels == 1)
  1255. {
  1256. pchB = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
  1257. while (lSamples-- > 0)
  1258. {
  1259. chTmp = *pchA;
  1260. *pchA++ = *--pchB;
  1261. *pchB = chTmp;
  1262. }
  1263. }
  1264. else
  1265. {
  1266. pchB = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - 1);
  1267. while (lSamples-- > 0)
  1268. {
  1269. chTmp = *pchA;
  1270. *pchA = *pchB;
  1271. *pchB = chTmp;
  1272. chTmp = pchA[1];
  1273. pchA[1] = pchB[1];
  1274. pchB[1] = chTmp;
  1275. pchA += 2;
  1276. pchB -= 2;
  1277. }
  1278. }
  1279. }
  1280. else
  1281. {
  1282. piA = (short *) gpWaveSamples;
  1283. if (gpWaveFormat->nChannels == 1)
  1284. {
  1285. piB = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid));
  1286. while (lSamples-- > 0)
  1287. {
  1288. iTmp = *piA;
  1289. *piA++ = *--piB;
  1290. *piB = (short)iTmp;
  1291. }
  1292. }
  1293. else
  1294. {
  1295. piB = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - 1));
  1296. while (lSamples-- > 0)
  1297. {
  1298. iTmp = *piA;
  1299. *piA = *piB;
  1300. *piB = (short)iTmp;
  1301. iTmp = piA[1];
  1302. piA[1] = piB[1];
  1303. piB[1] = (short)iTmp;
  1304. piA += 2;
  1305. piB -= 2;
  1306. }
  1307. }
  1308. }
  1309. /* move the current position so it corresponds to the same point
  1310. * in the audio as it did before the reverse operation
  1311. */
  1312. glWavePosition = glWaveSamplesValid - glWavePosition;
  1313. EndWaveEdit(TRUE);
  1314. if (hcurPrev != NULL)
  1315. SetCursor(hcurPrev);
  1316. /* update the display */
  1317. UpdateDisplay(TRUE);
  1318. }
  1319. #if defined(REVERB)
  1320. /* AddReverb()
  1321. *
  1322. * Add reverberation to samples in the wave buffer.
  1323. * Very similar to add echo, but instead of adding a single
  1324. * shot we
  1325. * 1. have multiple echoes
  1326. * 2. Have feedback so that each echo also generates an echo
  1327. * Danger: Because some of the echo times are short, there
  1328. * is likely to be high correlation between the wave
  1329. * at the source and destination points. In this case
  1330. * we don't get an echo at all, we get a resonance.
  1331. * The effect of a large hall DOES give resonances,
  1332. * but we should scatter them about to avoid making
  1333. * any sharp resonance.
  1334. * The first echo is also chosen to be long enough that
  1335. * its primary resonance will be below any normal speaking
  1336. * voice. 20mSec is 50Hz and an octave below bass range.
  1337. * Low levels of sound suffer badly from quantisation noise
  1338. * which can get quite bad. For this reason it's probably
  1339. * better to have the multipliers as powers of 2.
  1340. *
  1341. * Cheat: The reverb does NOT extend the total time (no realloc (yet).
  1342. *
  1343. * This takes a lot of compute - and is not really very much different
  1344. * in sound to AddEcho. Conclusion -- NOT IN PRODUCT.
  1345. *
  1346. */
  1347. void FAR PASCAL
  1348. AddReverb(void)
  1349. {
  1350. HCURSOR hcurPrev = NULL; // cursor before hourglass
  1351. long lSamples; // no. samples to modify
  1352. int iAmpSrc; // current source sample amplitude
  1353. int iAmpDst; // current destination sample amplitude
  1354. int i;
  1355. typedef struct
  1356. { long Offset; // delay in samples
  1357. long Delay; // delay in mSec
  1358. int Vol; // volume multiplier in units of 1/256
  1359. } ECHO;
  1360. #define CREVERB 3
  1361. ECHO Reverb[CREVERB] = { 0, 18, 64
  1362. , 0, 64, 64
  1363. };
  1364. if (!IsWaveFormatPCM(gpWaveFormat))
  1365. return;
  1366. BeginWaveEdit();
  1367. /* Convert millisec figures into samples */
  1368. for (i=0; i<CREVERB; ++i)
  1369. { Reverb[i].Offset = MulDiv( Reverb[i].Delay
  1370. , gpWaveFormat->nSamplesPerSec
  1371. , 1000L
  1372. );
  1373. // I think this could have the effect of putting the reverb
  1374. // from one stereo channel onto the other one sometimes.
  1375. // It's a feature! (Fix is to make Offset always even)
  1376. }
  1377. if (lSamples <= 0L) // nothing to do?
  1378. return; // don't set dirty flag
  1379. /* show hourglass cursor */
  1380. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1381. lSamples = glWaveSamplesValid * gpWaveFormat->nChannels;
  1382. /* Work through the buffer left to right adding in the reverbs */
  1383. if (((LPPCMWAVEFORMAT)gpWaveFormat)->wBitsPerSample == 8)
  1384. {
  1385. BYTE * pbSrc; // pointer into source part of buffer
  1386. BYTE * pbDst; // pointer into destination part
  1387. int iSample; // destination sample
  1388. for (i=0; i<CREVERB; ++i)
  1389. { long cSamp; // loop counter
  1390. int Vol = Reverb[i].Vol;
  1391. pbSrc = gpWaveSamples;
  1392. pbDst = gpWaveSamples+Reverb[i].Offset; // but elsewhere if realloc
  1393. cSamp = lSamples-Reverb[i].Offset;
  1394. while (cSamp-- > 0)
  1395. {
  1396. iAmpSrc = (*pbSrc) - 128;
  1397. iSample = *pbDst + MulDiv(iAmpSrc, Vol, 256);
  1398. *pbDst = (iSample < 0 ? 0 : (iSample > 255 ? 255 : iSample));
  1399. ++pbSrc;
  1400. ++pbDst;
  1401. }
  1402. }
  1403. }
  1404. else
  1405. {
  1406. int short * piSrc; // pointer into source part of buffer
  1407. int short * piDst; // pointer into destination part
  1408. long lSample;// destination sample
  1409. piSrc = gpWaveSamples;
  1410. piDst = gpWaveSamples;
  1411. while (lSamples-- > 0)
  1412. {
  1413. iAmpSrc = *piSrc;
  1414. for (i=0; i<CREVERB; ++i)
  1415. { int short * piD = piDst + Reverb[i].Offset; // !!not win16
  1416. lSample = *piD + MulDiv(iAmpSrc, Reverb[i].Vol, 256);
  1417. *piDst = (short) ( lSample < -32768L
  1418. ? -32768
  1419. : (lSample > 32767L ? 32767 : (short) lSample)
  1420. );
  1421. }
  1422. ++piSrc;
  1423. ++piDst;
  1424. }
  1425. }
  1426. EndWaveEdit(TRUE);
  1427. if (hcurPrev != NULL)
  1428. SetCursor(hcurPrev);
  1429. /* update the display */
  1430. UpdateDisplay(TRUE);
  1431. } /* AddReverb */
  1432. #endif //REVERB
  1433.