home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / pegase_src / inputstreamc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-15  |  43.7 KB  |  1,540 lines

  1. /*
  2. **
  3. ** InputStreamC.cpp
  4. **
  5. ** $VER: InputStreamC.cpp 1.4 (17.06.99)
  6. **
  7. ** $Revision: 1.3 $
  8. ** $State: Exp $
  9. ** $Date: 1998/08/16 19:03:37 $
  10. **
  11. */
  12.  
  13.  
  14. //----------------------------------------------------------------------------------------------------
  15.  
  16. /// Includes
  17.  
  18. #ifndef  _INCLUDE_STDLIB_H
  19. #include <stdlib.h>
  20. #endif
  21.  
  22. #ifndef  _INCLUDE_MATH_H
  23. #include <math.h>
  24. #endif
  25.  
  26. #ifndef  CLIB_DOS_PROTOS_H
  27. #include <clib/dos_protos.h>
  28. #endif
  29.  
  30. #ifndef  _PEGASE_HPP
  31. #include "Pegase.hpp"
  32. #endif
  33.  
  34. #ifndef  _INPUTSTREAM_CLASS_HPP
  35. #include "InputStreamC.hpp"
  36. #endif
  37.  
  38. #ifndef  _MEMORY_HPP
  39. #include "Memory.hpp"
  40. #endif
  41.  
  42. ///
  43.  
  44.  
  45. // Fonctions permettant de convertir des données au format Intel vers le format Motorola (et inversement)
  46.  
  47. inline WORD _getword(WORD w)
  48. {
  49.     return ( (w >> 8) + (w * 256) );
  50. }
  51.  
  52. inline LONG _getlong(LONG l)
  53. {
  54.     return ( ((l & 0xFF000000) >> 24) + ((l & 0x00FF0000) >> 8) + ((l & 0x0000FF00) * 256) + ((l & 0x000000FF) << 24) );
  55. }
  56.  
  57.  
  58. //----------------------------------------------------------------------------------------------------
  59.  
  60. // La fonction Seek() ne fonctionne pas correctement avec le FileSystem v36/37.
  61. // Voir les Autodocs pour le détail.
  62.  
  63. LONG NewSeek(BPTR file, LONG position, LONG offset)
  64. {
  65.     LONG p = ::Seek(file, position, offset);
  66.     if (IoErr()) p = -1;
  67.     return p;
  68. }
  69.  
  70.  
  71. //----------------------------------------------------------------------------------------------------
  72. //======================================= Classe InputStreamC ========================================
  73. //----------------------------------------------------------------------------------------------------
  74.  
  75. /// InputStreamC::AllocStreamBuffer()
  76. /****** Class InputStreamC/AllocStreamBuffer ********************************
  77. *
  78. *   NAME
  79. *   InputStreamC::AllocStreamBuffer -- Allouer le tampon de lecture.
  80. *
  81. *   SYNOPSIS
  82. *   ErrorCode = InputStreamC::AllocStreamBuffer()
  83. *
  84. *   e_IoErrors InputStreamC::AllocStreamBuffer();
  85. *
  86. *   FUNCTION
  87. *   Alloue le tampon de lecture pour le flux d'entrée. Ce tampon est aligné
  88. *   sur une frontière de page particulière, permettant ainsi certaines opti-
  89. *   misations suivant le CPU utilisé.
  90. *
  91. *   La taille du tampon est fixe, déterminée à la compilation. C'est un mul-
  92. *   tiple entier de la taille de chaque page attendue par l'encodeur.
  93. *
  94. *   RESULT
  95. *   ErrorCode - IOERR_NONE ou IOERR_NO_MEMORY;
  96. *
  97. *   NOTES
  98. *   Plusieurs fonctions assument que la taille du tampon de lecture est un
  99. *   multiple de la taille de chaque page attendue par l'encodeur.
  100. *
  101. *   SEE ALSO
  102. *   InputStreamC::FreeStreamBuffer()
  103. *
  104. *****************************************************************************
  105. *
  106. */
  107.  
  108.  
  109. e_IoErrors InputStreamC::AllocStreamBuffer()
  110. {
  111.     const ULONG iBufferSize = INPUT_BUFF_SIZE + (istr_iRollGap * 2);
  112.  
  113.     if ( (istr_pBufferAddr = (WORD *) AllocAlignedBuffer(iBufferSize)) )
  114.     {
  115.         istr_iBufferSize = INPUT_BUFF_SIZE;
  116.         istr_pBufferAddr += istr_iRollGap;
  117.         istr_pCurrentPos = istr_pUpperLimit = istr_pBufferAddr + (istr_iBufferSize >> 1);
  118.         return IOERR_NONE;
  119.     }
  120.  
  121.     SetIoError(IOERR_NO_MEMORY);
  122.     return IOERR_NO_MEMORY;
  123. }
  124. ///
  125. /// InputStreamC::FreeStreamBuffer()
  126. /****** Class InputStreamC/FreeStreamBuffer *********************************
  127. *
  128. *   NAME
  129. *   InputStreamC::FreeStreamBuffer -- Libérer le tampon de lecture.
  130. *
  131. *   SYNOPSIS
  132. *   InputStreamC::FreeStreamBuffer()
  133. *
  134. *   void InputStreamC::FreeStreamBuffer();
  135. *
  136. *   FUNCTION
  137. *   Libère le tampon de lecture utilisé par le flux d'entrée (à condition
  138. *   qu'il ait été effectivement alloué).
  139. *
  140. *   SEE ALSO
  141. *   InputStreamC::AllocStreamBuffer()
  142. *
  143. *****************************************************************************
  144. *
  145. */
  146.  
  147.  
  148. void InputStreamC::FreeStreamBuffer()
  149. {
  150.     if (istr_pBufferAddr)
  151.     {
  152.         FreeAlignedBuffer(istr_pBufferAddr - istr_iRollGap);
  153.         istr_pBufferAddr = NULL;
  154.     }
  155. }
  156. ///
  157. /// InputStreamC::RollBuffer()
  158. /****** Class InputStreamC/RollBuffer ***************************************
  159. *
  160. *   NAME
  161. *   InputStreamC::RollBuffer -- "Enrouler le tampon de lecture"
  162. *
  163. *   SYNOPSIS
  164. *   InputStreamC::RollBuffer()
  165. *
  166. *   void InputStreamC::RollBuffer();
  167. *
  168. *   FUNCTION
  169. *   Recopie les dernières données du tampon dans la partie réservée en tête
  170. *   de celui-ci. La taille du bloc transferé correspond à la taille du bloc
  171. *   d'entête.
  172. *
  173. *****************************************************************************
  174. *
  175. */
  176.  
  177.  
  178. void InputStreamC::RollBuffer()
  179. {
  180.     if (istr_iRollGap)
  181.     {
  182.         ULONG  gap = istr_iRollGap;
  183.         ULONG *dst = (ULONG *) (istr_pBufferAddr - gap);
  184.         ULONG *src = dst + (istr_iBufferSize >> 2);
  185.  
  186.         for (; gap > 0; gap--)
  187.             *dst++ = *src++;
  188.     }
  189. }
  190. ///
  191. /// InputStreamC::OpenStream()
  192. /****** Class InputStreamC/OpenStream ***************************************
  193. *
  194. *   NAME
  195. *   InputStreamC::OpenStream -- Ouvre le fichier à encoder.
  196. *
  197. *   SYNOPSIS
  198. *   ErrorCode = InputStreamC::OpenStream()
  199. *
  200. *   e_IoErrors InputStreamC::OpenStream();
  201. *
  202. *   FUNCTION
  203. *   Ouvre le fichier à encoder en lecture.
  204. *
  205. *   RESULT
  206. *   ErrorCode - Code d'erreur (IOERR_#?)
  207. *
  208. *   NOTES
  209. *   Fonction virtuelle.
  210. *
  211. *   SEE ALSO
  212. *   IFF_AudioC::OpenStream()
  213. *   InputStreamC::CloseStream()
  214. *
  215. *****************************************************************************
  216. *
  217. */
  218.  
  219.  
  220. e_IoErrors InputStreamC::OpenStream()
  221. {
  222.     e_IoErrors IOErr = IOERR_NONE;
  223.     istr_wEOF = istr_wContinue = FALSE;
  224.  
  225.     // Ouvrir le fichier audio. On change de répertoire pour s'assurer qu'on adresse
  226.     // bien le bon fichier.
  227.     // istr_iIoError reçoit une copie du code d'erreur du DOS après chaque opération de
  228.     // façon à pouvoir contrôler que l'objet a été crée correctement.
  229.     // Par la même occasion, istr_bpFileHandle reste NULL si le fichier n'a pas pu être
  230.     // ouvert.
  231.  
  232.     if ( (istr_bpNewDirLock = ::Lock((STRPTR) GetPathName(), ACCESS_READ)) )
  233.     {
  234.         istr_bpOldDirLock = ::CurrentDir(istr_bpNewDirLock);
  235.  
  236.         if ( (istr_bpFileHandle = ::Open((STRPTR) GetFileName(), MODE_OLDFILE)) == 0)
  237.             IOErr = IOERR_OPEN;
  238.     }
  239.     else IOErr = IOERR_DOS;
  240.  
  241.     SetIoError(IOErr, IoErr());
  242.  
  243.     return IOErr;
  244. }
  245. ///
  246. /// InputStreamC::CloseStream()
  247. /****** Class InputStreamC/CloseStream **************************************
  248. *
  249. *   NAME
  250. *   InputStreamC::CloseStream -- Ferme le fichier à encoder.
  251. *
  252. *   SYNOPSIS
  253. *   InputStreamC::CloseStream()
  254. *
  255. *   void InputStreamC::CloseStream();
  256. *
  257. *   FUNCTION
  258. *   Ferme le fichier à encoder. Cette fonction peut être appelée même si le
  259. *   fichier a déjà été fermé, ou lorsqu'il n'a pas été ouvert.
  260. *
  261. *   NOTES
  262. *   Fonction virtuelle
  263. *
  264. *   SEE ALSO
  265. *   IFF_AudioC::CloseStream()
  266. *   InputStreamC::OpenStream()
  267. *
  268. *****************************************************************************
  269. *
  270. */
  271.  
  272.  
  273. void InputStreamC::CloseStream()
  274. {
  275.     if (istr_bpFileHandle)
  276.     {
  277.         ::Close(istr_bpFileHandle);
  278.         istr_bpFileHandle = NULL;
  279.     }
  280.  
  281.     if (istr_bpNewDirLock)
  282.     {
  283.         ::CurrentDir(istr_bpOldDirLock);
  284.         ::UnLock(istr_bpNewDirLock);
  285.         istr_bpOldDirLock = istr_bpNewDirLock = 0;
  286.     }
  287. }
  288. ///
  289. /// InputStreamC::SeekToAudio()
  290. /****** Class InputStreamC/SeekToAudio **************************************
  291. *
  292. *   NAME
  293. *   InputStreamC::SeekToAudio -- Préparer la lecture du bloc audio.
  294. *
  295. *   SYNOPSIS
  296. *   Result = InputStreamC::SeekToAudio()
  297. *
  298. *   bool InputStreamC::SeekToAudio();
  299. *
  300. *   FUNCTION
  301. *   Positionne le pointeur de lecture au début du bloc de données audio.
  302. *   Le fichier doit avoir été ouvert au préalable !
  303. *
  304. *   RESULT
  305. *   Result - FALSE en cas d'erreur.
  306. *
  307. *   NOTES
  308. *   Fonction virtuelle.
  309. *
  310. *   SEE ALSO
  311. *   IFF_AudioC::SeekToAudio()
  312. *   WAV_AudioC::SeekToAudio()
  313. *
  314. *****************************************************************************
  315. *
  316. */
  317.  
  318.  
  319. int InputStreamC::SeekToAudio()
  320. {
  321.     /*
  322.     if (NewSeek(istr_bpFileHandle, 0L, OFFSET_BEGINING) >= 0) return TRUE;
  323.  
  324.     return FALSE;
  325.     */
  326.     return TRUE;
  327. }
  328. ///
  329. /// InputStreamC::FillBuffer()
  330. /****** Class InputStreamC/FillBuffer ***************************************
  331. *
  332. *   NAME
  333. *   InputStreamC::FillBuffer -- Remplir le tampon de lecture.
  334. *
  335. *   SYNOPSIS
  336. *   BytesRead = InputStreamC::FillBuffer()
  337. *
  338. *   LONG InputStreamC::FillBuffer();
  339. *
  340. *   FUNCTION
  341. *   Remplis le tampon de lecture avec de nouveaux échantillons.
  342. *
  343. *   RESULT
  344. *   BytesRead - Nombre d'octets lus, ZERO si la fin du fichier a été rencon-
  345. *   trée, ou -1 en cas d'erreur.
  346. *
  347. *   Le fichier doit avoir été ouvert au préalable, et le tampon de lecture
  348. *   doit avoir été alloué. Aucune vérification n'est effectuée sur ces deux
  349. *   conditions !
  350. *
  351. *   NOTES
  352. *   Fonction virtuelle
  353. *
  354. *   SEE ALSO
  355. *   IFF_AudioC::FillBuffer()
  356. *
  357. *****************************************************************************
  358. *
  359. */
  360.  
  361.  
  362. LONG InputStreamC::FillBuffer()
  363. {
  364.     RollBuffer();
  365.     return Read(istr_bpFileHandle, istr_pBufferAddr, istr_iBufferSize);
  366. }
  367. ///
  368. /// InputStreamC::ReadSamples()
  369. /****** Class InputStreamC/ReadSamples **************************************
  370. *
  371. *   NAME
  372. *   InputStreamC::ReadSamples -- Obtenir le bloc suivant.
  373. *
  374. *   SYNOPSIS
  375. *   BlockAddr = InputStreamC::ReadSamples(iNumSamples)
  376. *
  377. *   WORD * InputStreamC::ReadSamples(UWORD);
  378. *
  379. *   FUNCTION
  380. *   Retourne un pointeur vers le bloc d'échantillons suivant, ou NULL en cas
  381. *   d'erreur (problème de lecture, ou fin de fichier atteinte).
  382. *   La fonction s'occupe du remplissage du tampon lorsque c'est nécessaire,
  383. *   à moins que la fin du fichier n'ait été atteinte.
  384. *
  385. *   Le flux d'entrée doit avoir été ouvert au préalable, et la tampon doit
  386. *   avoir été alloué. Aucun contrôle n'est fait concernant ces conditions !
  387. *
  388. *   INPUTS
  389. *   iNumSamples - Nombre d'échantillons à lire.
  390. *
  391. *   RESULT
  392. *   BlockAddr - Adresse du prochain bloc, ou NULL. GetIoError() renseigne sur
  393. *   le code d'erreur lorsque le pointeur retourné vaut NULL.
  394. *   Le couple IOERR_WARN + ERROR_NO_MORE_ENTRIES indique que l'on a rencontré
  395. *   la fin du fichier.
  396. *
  397. *   NOTES
  398. *   Cette fonction repose sur le fait que la taille du tampon est un multiple
  399. *   entier de toutes les tailles de bloc possibles. Voir AllocStreamBuffer().
  400. *
  401. *****************************************************************************
  402. *
  403. */
  404.  
  405.  
  406. WORD *InputStreamC::ReadSamples(UWORD iNumSamples)
  407. {
  408.     if (!istr_wEOF)
  409.     {
  410.         if (istr_iSamplesRead == 0)
  411.         {
  412.             // Le tampon est vide...
  413.  
  414.             if (!istr_wContinue)
  415.             {
  416.                 // Procéder au premier remplissage du tampon.
  417.  
  418.                 if (!SeekToAudio()) goto Abort;
  419.  
  420.                 istr_wContinue = TRUE;
  421.             }
  422.  
  423.             // Remplir le tampon avec les échantillons suivant.
  424.  
  425.             istr_iSamplesRead = FillBuffer();
  426.  
  427.             if (istr_iSamplesRead < 0)  goto Abort;
  428.             if (istr_iSamplesRead == 0)
  429.             {
  430.                 SetIoError(IOERR_WARN, ERROR_NO_MORE_ENTRIES);
  431.                 istr_wEOF = TRUE;                   // Fin de fichier atteinte.
  432.                 goto Exit_;
  433.             }
  434.             istr_iSamplesRead >>= 1;                // 16 bits par échantillon.
  435.         }
  436.         return GetNextBlockAddr(iNumSamples);
  437.     }
  438.  
  439. Abort:
  440.     SetIoError(IOERR_DOS, ::IoErr());
  441.  
  442. Exit_:
  443.     return NULL;
  444. }
  445. ///
  446. /// InputStreamC::GetNextBlockAddr()
  447. /****** InputStreamC/GetNextBlockAddr ***************************************
  448. *
  449. *   NAME
  450. *   GetNextBlockAddr -- Obtenir l'adresse du prochain bloc (Privée).
  451. *
  452. *   SYNOPSIS
  453. *   NextBlock = GetNextBlockAddr(iNumSamples)
  454. *
  455. *   WORD *GetNextBlockAddr(UWORD);
  456. *
  457. *   FUNCTION
  458. *   Mets à jour les membres privés en rapport avec la gestion du tampon d'
  459. *   entrée.
  460. *   Lorsque le tampon vient d'être rempli pour la première fois, ou lorque l'
  461. *   adresse du prochain bloc serait hors du tampon, le prochain bloc se situe
  462. *   alors en début de tampon.
  463. *   Si le bloc courant ne contient pas assez d'échantillons, il est completé
  464. *   avec des 0.
  465. *
  466. *   Le nombre d'échantillons traités est mis à jour par cette fonction.
  467. *
  468. *   INPUTS
  469. *   iNumSamples - Nombre d'échantillons.
  470. *
  471. *   RESULT
  472. *   NextBlock - Pointeur vers le bloc de données à traiter.
  473. *
  474. *   NOTES
  475. *   Cette fonction repose sur le fait que la taille du tampon d'entrée est un
  476. *   multiple entier de toutes les tailles de bloc possibles.
  477. *   void AllocStreamBuffer()
  478. *
  479. *****************************************************************************
  480. *
  481. */
  482.  
  483.  
  484. WORD *InputStreamC::GetNextBlockAddr(UWORD iNumSamples)
  485. {
  486.     istr_pCurrentPos += iNumSamples;
  487.  
  488.     if (istr_pCurrentPos >= istr_pUpperLimit)
  489.     {
  490.         istr_pCurrentPos = istr_pBufferAddr;    // Réinitialiser le pointeur courant en début de bloc
  491.     }                                           // si le dernier bloc du tampon a été traité.
  492.  
  493.     istr_iSmplProcessed += (iNumSamples > istr_iSamplesRead) ? istr_iSamplesRead : iNumSamples;
  494.  
  495.     // Recalculer le facteur de progression si nécessaire.
  496.  
  497.     if (istr_roFileInfo.GetNumSamples() && istr_iSmplProcessed >= istr_iNextLimit)
  498.     {
  499.         istr_iProgressValue = istr_iSmplProcessed * 100 / istr_roFileInfo.GetNumSamples();
  500.         istr_iNextLimit += istr_iStepMin;
  501.     }
  502.  
  503.     // Compléter le bloc s'il est trop court.
  504.  
  505.     WORD *p = istr_pBufferAddr + istr_iSamplesRead;
  506.  
  507.     for (; istr_iSamplesRead < iNumSamples; istr_iSamplesRead++)
  508.         *p++ = 0;
  509.  
  510.     istr_iSamplesRead -= iNumSamples;
  511.  
  512.     return istr_pCurrentPos;
  513. }
  514. ///
  515.  
  516. //----------------------------------------------------------------------------------------------------
  517. //======================================== Classe RAW_AudioC =========================================
  518. //----------------------------------------------------------------------------------------------------
  519. //
  520. //  Fonctions spécialisées dans la gestion des fichiers RAW/PCM
  521.  
  522. /// RAW_AudioC/GetFileInfos()
  523. /****** Class RAW_AudioC/GetFileInfos ***************************************
  524. *
  525. *   NAME
  526. *   RAW_AudioC::GetFileInfos -- Analyse un fichier RAW/PCM
  527. *
  528. *   SYNOPSIS
  529. *   Result = RAW_AudioC::GetFileInfos()
  530. *
  531. *   bool RAW_AudioC::GetFileInfos();
  532. *
  533. *   FUNCTION
  534. *   Analyse le fichier afin de connaître le nombre d'échantillons.
  535. *
  536. *   RESULT
  537. *   Result - FALSE en cas d'erreur.
  538. *
  539. *   NOTES
  540. *   Surdéfinition d'une fonction virtuelle
  541. *
  542. *   - Le nombre d'échantillons est déterminé par la taille du fichier.
  543. *   - Les échantillons sont considérés comme étant codés sur 16 bits et au
  544. *     format Motorola.
  545. *   - Le fichier audio est considéré comme étant en mono.
  546. *   - La fréquence d'échantillonage est indéterminée.
  547. *
  548. *   SEE ALSO
  549. *   AIFF_AudioC::GetFileInfos()
  550. *   MAUD_AudioC::GetFileInfos()
  551. *   CDDA_AudioC::GetFileInfos()
  552. *   WAV_AudioC::GetFileInfos()
  553. *
  554. *****************************************************************************
  555. *
  556. */
  557.  
  558.  
  559. int RAW_AudioC::GetFileInfos()
  560. {
  561.     int  success;
  562.     ULONG NumFrames = istr_roFileInfo.GetFileLength() >> 1;
  563.  
  564.     SetNumFrames(NumFrames);
  565.     if ( !(success = istr_roFileInfo.OverrideSettings(0, 1) ))  // Mode mono.
  566.         SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  567.  
  568.     istr_roFileInfo.SetEncodingMode(MONO);
  569.     SetAudioFormat(FORMAT_MOTOROLA_MONO);
  570.  
  571.     return success;
  572. }
  573. ///
  574. /// RAW_AudioC/OverrideSettings()
  575. /****** Class RAW_AudioC/OverrideSettings ***********************************
  576. *
  577. *   NAME
  578. *   RAW_AudioC::OverrideSettings -- Modifier les réglages du fichier.
  579. *
  580. *   SYNOPSIS
  581. *   Result = RAW_AudioC::OverrideSettings(iSampleFreq, bChannels)
  582. *
  583. *   bool RAW_AudioC::OverrideSettings(ULONG, UBYTE);
  584. *
  585. *   FUNCTION
  586. *   Modifie la fréquence d'échantillonage du fichier audio.
  587. *   Puisque les fichiers RAW/PCM sont censés être en mono, le nombre de
  588. *   canaux spécifié est ignoré (toujours 1).
  589. *
  590. *   INPUTS
  591. *   iSampleFreq - Fréquence d'échantillonage (Hz).
  592. *   bChannels   - IGNORE
  593. *
  594. *   RESULT
  595. *   Result - FALSE en cas d'erreur.
  596. *
  597. *   NOTES
  598. *   Surdéfinition d'une fonction virtuelle.
  599. *
  600. *   Un fichier RAW/PCM est supposé toujours être en mono.
  601. *
  602. *   SEE ALSO
  603. *   CDDA_AudioC::GetFileInfos()
  604. *   IFF_AudioC::GetFileInfos()
  605. *   WAV_AudioC::GetFileInfos()
  606. *
  607. *****************************************************************************
  608. *
  609. */
  610.  
  611.  
  612. int RAW_AudioC::OverrideSettings(ULONG iSampleFreq, UBYTE bChannels)
  613. {
  614.     return istr_roFileInfo.OverrideSettings(iSampleFreq, 1);
  615. }
  616. ///
  617.  
  618. //----------------------------------------------------------------------------------------------------
  619. //======================================== Classe IFF_AudioC =========================================
  620. //----------------------------------------------------------------------------------------------------
  621. //
  622. //  Fonctions de base pour la gestion des fichiers IFF.
  623.  
  624. /// IFF_AudioC::OpenStream()
  625. /****** Class IFF_AudioC/OpenStream *****************************************
  626. *
  627. *   NAME
  628. *   IFF_AudioC::OpenStream -- Ouvrir le flux IFF en lecture.
  629. *
  630. *   SYNOPSIS
  631. *   Error = IFF_AudioC::OpenStream()
  632. *
  633. *   e_IoErrors IFF_AudioC::OpenStream();
  634. *
  635. *   FUNCTION
  636. *   Initialise et ouvre en lecture un flux IFF.
  637. *
  638. *   RESULT
  639. *   Error - Code d'erreur (IOERR_#?).
  640. *
  641. *   NOTES
  642. *   Surdéfinition d'une fonction virtuelle
  643. *
  644. *   SEE ALSO
  645. *   InputStreamC::OpenStream()
  646. *   IFF_AudioC::CloseStream()
  647. *
  648. *****************************************************************************
  649. *
  650. */
  651.  
  652.  
  653. e_IoErrors IFF_AudioC::OpenStream()
  654. {
  655.     e_IoErrors IOErr = IOERR_NONE;
  656.     LONG i2ndError = 0;
  657.  
  658.     // Ouvrir le fichier audio.
  659.  
  660.     if ( (IOErr = InputStreamC::OpenStream()) != IOERR_NONE) return IOErr;
  661.  
  662.     // Ouvrir le flux IFF.
  663.  
  664.     if ( (istr_pIFF = AllocIFF()) )
  665.     {
  666.         istr_pIFF->iff_Stream = istr_bpFileHandle;
  667.         ::InitIFFasDOS(istr_pIFF);
  668.         if ( (i2ndError = ::OpenIFF(istr_pIFF, IFFF_READ)) == 0) return IOERR_NONE;
  669.  
  670.         // Erreur pendant l'ouverture : Libérer les ressources allouées partiellement.
  671.  
  672.         ::FreeIFF(istr_pIFF);
  673.         istr_pIFF = NULL;
  674.     }
  675.     else i2ndError = IFFERR_NOMEM;
  676.  
  677.     SetIoError(IOERR_IFF, i2ndError);
  678.     return IOERR_IFF;
  679. }
  680. ///
  681. /// IFF_AudioC::CloseStream()
  682. /****** Class IFF_AudioC/CloseStream ****************************************
  683. *
  684. *   NAME
  685. *   IFF_AudioC::CloseStream -- Ferme un flux IFF
  686. *
  687. *   SYNOPSIS
  688. *   IFF_AudioC::CloseStream()
  689. *
  690. *   void IFF_AudioC::CloseStream();
  691. *
  692. *   FUNCTION
  693. *   Ferme et libère un flux IFF. Cette fonction peut être appelée même si le
  694. *   flux IFF est déjà fermé ou lorsqu'il n'a pas été ouvert.
  695. *
  696. *   NOTES
  697. *   Surdéfinition d'une fonction virtuelle
  698. *
  699. *   SEE ALSO
  700. *   InputStreamC::CloseStream()
  701. *   IFF_AudioC::OpenStream()
  702. *
  703. *****************************************************************************
  704. *
  705. */
  706.  
  707.  
  708. void IFF_AudioC::CloseStream()
  709. {
  710.     // Fermer le flux IFF
  711.  
  712.     if (istr_pIFF)
  713.     {
  714.         ::CloseIFF(istr_pIFF);
  715.         ::FreeIFF(istr_pIFF);
  716.         istr_pIFF = 0;
  717.     }
  718.  
  719.     // Fermer le fichier audio.
  720.  
  721.     InputStreamC::CloseStream();
  722. }
  723. ///
  724. /// IFF_AudioC::SeekToAudio()
  725. /****** Class IFF_AudioC/SeekToAudio ****************************************
  726. *
  727. *   NAME
  728. *   IFF_AudioC::SeekToAudio -- Préparer la lecture du bloc audio.
  729. *
  730. *   SYNOPSIS
  731. *   Result = IFF_AudioC::SeekToAudio()
  732. *
  733. *   bool IFF_AudioC::SeekToAudio();
  734. *
  735. *   FUNCTION
  736. *   Positionne le pointeur de lecture au début du bloc de données audio.
  737. *   Le flux IFF doit avoir été ouvert et initialisé avant d'appeler cette
  738. *   fonction.
  739. *
  740. *   RESULT
  741. *   Result - FALSE en cas d'erreur.
  742. *
  743. *   NOTES
  744. *   Surdéfinition d'une fonction virtuelle.
  745. *
  746. *   SEE ALSO
  747. *   InputStreamC::SeekToAudio()
  748. *   WAV_AudioC::SeekToAudio()
  749. *
  750. *****************************************************************************
  751. *
  752. *   Le format du chunk audio varie d'un type de fichier à l'autre. De fait,
  753. *   la fonction est capable de sauter les informations situées en début de
  754. *   chunk, et précédant les données audio attendues.
  755. *   A l'heure actuelle, les fichier MAUD ne possèdent aucune données en
  756. *   entête, alors que les fichiers AIFF contiennent une structure de 8 octets
  757. *   juste avant les données audio.
  758. *
  759. */
  760.  
  761.  
  762. int IFF_AudioC::SeekToAudio()
  763. {
  764.     const ULONG iBufferSize = sizeof(struct AIFF_SSND);     // Pour l'instant, cela correspond au maximum possible,
  765.                                                             // à savoir la taille de la structure AIFF_SSND.
  766.  
  767.     ContextNode *pCNode;
  768.     LONG i2ndError = 0;
  769.     char a_TempBuff[iBufferSize];
  770.  
  771.     if (    (i2ndError = ::StopChunk(istr_pIFF, istr_iTypeChunkID, istr_iDataChunkID)) == 0
  772.          && (i2ndError = ::ParseIFF(istr_pIFF, IFFPARSE_SCAN)) == 0)
  773.     {
  774.         pCNode = ::CurrentChunk(istr_pIFF);
  775.  
  776.         // S'il faut sauter des données au début du chunk, c'est le moment de le faire...
  777.  
  778.         for (LONG i = istr_iAudioDataOffset; i > 0 && i2ndError > 0; i -= iBufferSize)
  779.             i2ndError = ::ReadChunkBytes(istr_pIFF, a_TempBuff, iBufferSize);
  780.  
  781.         if (i2ndError == 0) return TRUE;
  782.     }
  783.  
  784.     // Placer les codes d'erreur.
  785.  
  786.     SetIoError(IOERR_IFF, i2ndError);
  787.     return FALSE;
  788. }
  789. ///
  790. /// IFF_AudioC::FillBuffer()
  791. /****** Class IFF_AudioC/FillBuffer *****************************************
  792. *
  793. *   NAME
  794. *   IFF_AudioC::FillBuffer -- Remplir le tampon de lecture.
  795. *
  796. *   SYNOPSIS
  797. *   BytesRead = IFF_AudioC::FillBuffer()
  798. *
  799. *   LONG IFF_AudioC::FillBuffer();
  800. *
  801. *   FUNCTION
  802. *   Remplis le tampon de lecture avec de nouveaux échantillons.
  803. *
  804. *   RESULT
  805. *   BytesRead - Nombre d'octets lus, ZERO si la fin du fichier a été rencon-
  806. *   trée, ou -1 en cas d'erreur.
  807. *
  808. *   Le fichier doit avoir été ouvert au préalable, et le tampon de lecture
  809. *   doit avoir été alloué. Aucune vérification n'est effectuée sur ces deux
  810. *   conditions !
  811. *
  812. *   NOTES
  813. *   Surdéfinition d'une fonction virtuelle
  814. *
  815. *   SEE ALSO
  816. *   InputStreamC::FillBuffer()
  817. *
  818. *****************************************************************************
  819. *
  820. */
  821.  
  822.  
  823. LONG IFF_AudioC::FillBuffer()
  824. {
  825.     RollBuffer();
  826.     return ::ReadChunkBytes(istr_pIFF, istr_pBufferAddr, istr_iBufferSize);
  827. }
  828. ///
  829. /// IFF_AudioC::ReadChunks()
  830. /****** Class IFF_AudioC/ReadChunks *****************************************
  831. *
  832. *   NAME
  833. *   IFF_AudioC::ReadChunks -- Lire le contenu d'un chunk précis.
  834. *
  835. *   SYNOPSIS
  836. *   Datas = IFF_AudioC::ReadChunks()
  837. *
  838. *   StoredProperty * IFF_AudioC::ReadChunks();
  839. *
  840. *   FUNCTION
  841. *   Recherche et charge les chunks du fichier IFF.
  842. *   Actuellement, la fonction effectue une copie du bloc d'entête du fichier
  843. *   IFF, et positionne le contexte sur le bloc de données audio.
  844. *
  845. *   RESULT
  846. *   Datas - Pointeur vers la structure StoredProperty décrivant le bloc d'
  847. *   entête, ou NULL en cas d'erreur.
  848. *
  849. *   NOTES
  850. *   Le fichier IFF doit avoir été ouvert au préalable.
  851. *
  852. *****************************************************************************
  853. *
  854. */
  855.  
  856.  
  857. StoredProperty *IFF_AudioC::ReadChunks()
  858. {
  859.     LONG i2ndError = 0;
  860.  
  861.     if (    (i2ndError = ::PropChunk(istr_pIFF, istr_iTypeChunkID, istr_iHeaderChunkID)) == 0
  862.          && (i2ndError = ::StopChunk(istr_pIFF,istr_iTypeChunkID, istr_iDataChunkID)) == 0
  863.          && (i2ndError = ::ParseIFF(istr_pIFF, IFFPARSE_SCAN) == 0))
  864.     {
  865.         return ::FindProp(istr_pIFF, istr_iTypeChunkID, istr_iHeaderChunkID);
  866.     }
  867.  
  868.     // Mémoriser les codes d'erreur.
  869.  
  870.     SetIoError(IOERR_IFF, i2ndError);
  871.     return NULL;
  872. }
  873. ///
  874. /// IFF_AudioC::CheckAudioChunk()
  875. /****** Class IFF_AudioC/CheckAudioChunk ************************************
  876. *
  877. *   NAME
  878. *   IFF_AudioC::CheckAudioChunk -- Contrôler la taille du chunk audio.
  879. *
  880. *   SYNOPSIS
  881. *   IFF_AudioC::CheckAudioChunk(iOffset)
  882. *
  883. *   void IFF_AudioC::CheckAudioChunk(ULONG);
  884. *
  885. *   FUNCTION
  886. *   Recherche le chunk audio associé au fichier IFF courant afin de contrôler
  887. *   sa taille par rapport au nombre d'échantillons spécifiés dans l'entête.
  888. *
  889. *   Si la taille ne correspond pas, le code d'erreur IOERR_WARN associé à
  890. *   ERROR_BAD_HUNK est placé.
  891. *
  892. *   INPUT
  893. *   iOffset - Nombre d'octets à sauter en début de chunk pour adresser les
  894. *   échantillons.
  895. *
  896. *   NOTES
  897. *   Le fichier IFF doit avoir été ouvert au préalable.
  898. *
  899. *****************************************************************************
  900. *
  901. */
  902.  
  903.  
  904. void IFF_AudioC::CheckAudioChunk(ULONG iOffset)
  905. {
  906.     ContextNode *pCNode;
  907.     ULONG        iSize;
  908.  
  909.     pCNode = ::CurrentChunk(istr_pIFF);
  910.     iSize = (pCNode->cn_Size - iOffset) >> 1;       // 16 bits par échantillons.
  911.  
  912.     if ( iSize != GetNumSamples() )
  913.     {
  914.         SetNumFrames( (GetNumChannels() == 1) ? iSize : iSize >> 1);
  915.         SetIoError(IOERR_WARN, ERROR_BAD_HUNK);
  916.     }
  917. }
  918. ///
  919.  
  920. //----------------------------------------------------------------------------------------------------
  921. //======================================== Classe AIFF_AudioC ========================================
  922. //----------------------------------------------------------------------------------------------------
  923. //
  924. //  Fonctions spécialisées dans la gestion des fichiers AIFF.
  925.  
  926. /// AIFF_AudioC::GetFileInfos()
  927. /****** Class AIFF_AudioC/GetFileInfos **************************************
  928. *
  929. *   NAME
  930. *   AIFF_AudioC::GetFileInfos -- Analyse un fichier AIFF.
  931. *
  932. *   SYNOPSIS
  933. *   Result = AIFF_AudioC::GetFileInfos()
  934. *
  935. *   bool AIFF_AudioC::GetFileInfos();
  936. *
  937. *   FUNCTION
  938. *   Analyse le fichier AIFF afin de connaître ses réglages particuliers, tels
  939. *   que le nombre de canaux, le nombre d'échantillons, la fréquence d'échan-
  940. *   tillonage, etc.
  941. *
  942. *   La fonction vérifie aussi que la taille du chunk audio est en accord avec
  943. *   le nombre d'échantillons annoncé dans l'entête du fichier.
  944. *
  945. *   RESULT
  946. *   Result - TRUE si les paramètres du fichier ont été lus, FALSE en cas d'
  947. *   erreur. GetIoError() permet de récupérer, dans ce dernier cas, un code
  948. *   d'erreur plus précis.
  949. *
  950. *   NOTES
  951. *   Surdéfinition d'une fonction virtuelle.
  952. *
  953. *   La fréquence d'échantillonage est obtenue avec une fonction simplifiée
  954. *   basée sur le format d'un nombre flottant (IEEE-754).
  955. *   Si le fichier AIFF n'est pas un fichier audio, ou si les échantillons ne
  956. *   sont pas codés sur 16 bits, ou si le nombre de canaux est supérieur à 2,
  957. *   alors le fichier AIFF est rejeté.
  958. *
  959. *   SEE ALSO
  960. *   MAUD_AudioC::GetFileInfos()
  961. *   CDDA_AudioC::GetFileInfos()
  962. *   RAW_AudioC::GetFileInfos()
  963. *   WAV_AudioC::GetFileInfos()
  964. *
  965. *****************************************************************************
  966. *
  967. *   AIFF : COMM = Chunk de description (obligatoire et unique).
  968. *          SSND = Chunk des données audio (unique).
  969. *
  970. */
  971.  
  972.  
  973. int AIFF_AudioC::GetFileInfos()
  974. {
  975.  
  976. // Structure des chunks AIFF.
  977.  
  978. struct IEEE_754 {short exponent;
  979.                  long  mantissa_hi;
  980.                  ULONG mantissa_lo;
  981.                 };
  982.  
  983. struct AIFF_COMM {short     NumChannels;        // Nombre de canaux (1, 2, 4, etc)
  984.                   ULONG     NumSampleFrames;    // Nombre d'échantillons par canal.
  985.                   short     SampleSize;         // Nombre de bits par échantillons.
  986.                   IEEE_754  SampleRate;         // Fréquence d'échantillonage.
  987.                  };
  988.  
  989.     int success = FALSE;
  990.  
  991.     if (OpenStream() == IOERR_NONE)
  992.     {
  993.         StoredProperty *pSP;
  994.  
  995.         // Décoder le chunk principal.
  996.  
  997.         if ( (pSP = ReadChunks()) )
  998.         {
  999.             AIFF_COMM *pCOMM = (AIFF_COMM *) pSP->sp_Data;
  1000.  
  1001.             //-----------------------------------------------------------------
  1002.  
  1003.             if (pCOMM->SampleSize == 16 && pCOMM->NumSampleFrames != 0L)
  1004.             {
  1005.                 // Décoder le format IEEE_754;
  1006.                 // On utilise les hypothèses suivantes :
  1007.                 // - La fréquence d'échantillonage est positive.
  1008.                 // - Elle est définie par un nombre entier.
  1009.  
  1010.                 WORD  e = (pCOMM->SampleRate.exponent & 0x7FFF) - 16383;
  1011.                 ULONG smplfreq = pCOMM->SampleRate.mantissa_hi;
  1012.  
  1013.                 if (e > 0 && e < 30 && pCOMM->NumChannels < 3)
  1014.                 {
  1015.                     smplfreq = (((smplfreq >> (30-e)) + 1 ) >> 1);
  1016.                     SetNumFrames(pCOMM->NumSampleFrames);
  1017.  
  1018.                     if ( !(success = istr_roFileInfo.OverrideSettings(smplfreq, pCOMM->NumChannels)) )
  1019.                         SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  1020.  
  1021.                     SetAudioFormat( (pCOMM->NumChannels == 1) ? FORMAT_MOTOROLA_MONO : FORMAT_MOTOROLA_STEREO );
  1022.  
  1023.                     CheckAudioChunk(sizeof(struct AIFF_SSND));
  1024.                     CloseStream();
  1025.                     return success;
  1026.                 }
  1027.             }
  1028.         }
  1029.         // Fichier AIFF non supporté.
  1030.  
  1031.         SetFileType(AFT_BAD_AIFF);
  1032.         SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  1033.         CloseStream();
  1034.     }
  1035.  
  1036.     return success;
  1037. }
  1038. ///
  1039.  
  1040. //----------------------------------------------------------------------------------------------------
  1041. //======================================== Classe MAUD_AudioC ========================================
  1042. //----------------------------------------------------------------------------------------------------
  1043. //
  1044. //  Fonctions spécialisées dans la gestion des fichiers MAUD.
  1045.  
  1046. /// Définitions
  1047. #define ID_MAUD 0x4D415544  /* 'MAUD' */    /* the FORM-ID */
  1048. #define ID_MHDR 0x4D484452  /* 'MHDR' */    /* file header chunk */
  1049. #define ID_MDAT 0x4D444154  /* 'MDAT' */    /* sample data chunk */
  1050. #define ID_MINF 0x4D494E46  /* 'MINF' */    /* optional channel info chunk (future) */
  1051.  
  1052. /* ---- the file header 'MHDR' */
  1053.  
  1054. struct MaudHeader {
  1055.     ULONG   mhdr_Samples;       /* number of samples stored in MDAT */
  1056.     UWORD   mhdr_SampleSizeC;   /* number of bits per sample as stored in MDAT */
  1057.     UWORD   mhdr_SampleSizeU;   /* number of bits per sample after decompression */
  1058.     ULONG   mhdr_RateSource;    /* clock source frequency (see maud.doc) */
  1059.     UWORD   mhdr_RateDevide;    /* clock devide           (see maud.doc) */
  1060.     UWORD   mhdr_ChannelInfo;   /* channel information (see below) */
  1061.     UWORD   mhdr_Channels;      /* number of channels (mono: 1, stereo: 2, ...) */
  1062.     UWORD   mhdr_Compression;   /* compression type (see below) */
  1063.     ULONG   mhdr_Reserved1;     /* MUST be set to 0 when saving */
  1064.     ULONG   mhdr_Reserved2;     /* MUST be set to 0 when saving */
  1065.     ULONG   mhdr_Reserved3;     /* MUST be set to 0 when saving */
  1066. };
  1067.  
  1068. /* ---- possible values for mhdr_ChannelInfo */
  1069.  
  1070. #define MCI_MONO            0   /* mono */
  1071. #define MCI_STEREO          1   /* stereo */
  1072. #define MCI_MULTIMONO       2   /* mono multichannel (channels can be 2, 3, 4, ...) */
  1073. #define MCI_MULTISTEREO     3   /* stereo multichannel (channels must be 4, 6, 8, ...) */
  1074. #define MCI_MULTICHANNEL    4   /* multichannel (requires additional MINF-chunks) (future) */
  1075.  
  1076. /* ---- possible values for mhdr_Compression */
  1077.  
  1078. #define MCOMP_NONE      0       /* no compression */
  1079. #define MCOMP_FIBDELTA  1       /* 'Fibonacci Delta Compression' as used in 8SVX */
  1080. #define MCOMP_ALAW      2       /* 16->8 bit, European PCM standard A-Law */
  1081. #define MCOMP_ULAW      3       /* 16->8 bit, American PCM standard µ-Law */
  1082. #define MCOMP_ADPCM2    4       /* 16->2 bit, ADPCM compression */
  1083. #define MCOMP_ADPCM3    5       /* 16->3 bit, ADPCM compression */
  1084. #define MCOMP_ADPCM4    6       /* 16->4 bit, ADPCM compression */
  1085. #define MCOMP_ADPCM5    7       /* 16->5 bit, ADPCM compression */
  1086. #define MCOMP_LONGDAT   8       /* 16->12 bit, used for DAT-longplay */
  1087. ///
  1088.  
  1089. /// MAUD_AudioC::GetFileInfos()
  1090. /****** Class MAUD_AudioC/GetFileInfos **************************************
  1091. *
  1092. *   NAME
  1093. *   MAUD_AudioC::GetFileInfos -- Analyse un fichier MAUD.
  1094. *
  1095. *   SYNOPSIS
  1096. *   Result = MAUD_AudioC::GetFileInfos()
  1097. *
  1098. *   bool MAUD_AudioC::GetFileInfos();
  1099. *
  1100. *   FUNCTION
  1101. *   Analyse le fichier MAUD afin de connaître ses réglages particuliers, tels
  1102. *   que le nombre de canaux, le nombre d'échantillons, la fréquence d'échan-
  1103. *   tillonage, etc.
  1104. *
  1105. *   RESULT
  1106. *   Result - TRUE si les paramètres du fichier ont été lus, FALSE en cas d'
  1107. *   erreur. GetIoError() permet de récupérer, dans ce dernier cas, un code
  1108. *   d'erreur plus précis.
  1109. *
  1110. *   NOTES
  1111. *   Surdéfinition d'une fonction virtuelle
  1112. *
  1113. *   Pour que le fichier MAUD soit accepté, il faut que les échantillons
  1114. *   soient codés sur 16 bits, qu'il y ait 1 ou 2 canaux audio, et que les
  1115. *   échantillons ne soient pas compressés.
  1116. *
  1117. *   SEE ALSO
  1118. *   AIFF_AudioC::GetFileInfos()
  1119. *   CDDA_AudioC::GetFileInfos()
  1120. *   RAW_AudioC::GetFileInfos()
  1121. *   WAV_AudioC::GetFileInfos()
  1122. *
  1123. *****************************************************************************
  1124. *
  1125. *   MAUD : MHDR = Chunk de description (obligatoire et unique).
  1126. *          MDAT = Chunk des données audio (unique).
  1127. *
  1128. */
  1129.  
  1130.  
  1131. int MAUD_AudioC::GetFileInfos()
  1132. {
  1133.     int success = FALSE;
  1134.  
  1135.     if (OpenStream() == IOERR_NONE)
  1136.     {
  1137.         StoredProperty *pSP;
  1138.  
  1139.         // Décoder le chunk principal.
  1140.  
  1141.         if ( (pSP = ReadChunks()) )
  1142.         {
  1143.             MaudHeader *pHDR = (MaudHeader *) pSP->sp_Data;
  1144.  
  1145.             //-----------------------------------------------------------------
  1146.  
  1147.             // On ne supporte que les fichiers MAUD 16 bits (sans compression).
  1148.  
  1149.             if (pHDR->mhdr_SampleSizeC == 16 && pHDR->mhdr_Compression == MCOMP_NONE)
  1150.             {
  1151.                 ULONG smplfreq = pHDR->mhdr_RateSource / pHDR->mhdr_RateDevide;
  1152.  
  1153.                 if (pHDR->mhdr_ChannelInfo == MCI_MONO || pHDR->mhdr_ChannelInfo == MCI_STEREO)
  1154.                 {
  1155.                     SetNumFrames(pHDR->mhdr_Samples);
  1156.                     success = istr_roFileInfo.OverrideSettings(smplfreq, pHDR->mhdr_Channels);
  1157.                     SetAudioFormat( (pHDR->mhdr_Channels == 1) ? FORMAT_MOTOROLA_MONO : FORMAT_MOTOROLA_STEREO );
  1158.  
  1159.                     if (!success) SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  1160.  
  1161.                     CheckAudioChunk(0L);
  1162.                     CloseStream();
  1163.                     return success;
  1164.                 }
  1165.             }
  1166.         }
  1167.         // Fichier MAUD non supporté.
  1168.  
  1169.         SetFileType(AFT_BAD_MAUD);
  1170.         SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  1171.         CloseStream();
  1172.     }
  1173.  
  1174.     return success;
  1175. }
  1176. ///
  1177.  
  1178. //----------------------------------------------------------------------------------------------------
  1179. //======================================== Classe CDDA_AudioC ========================================
  1180. //----------------------------------------------------------------------------------------------------
  1181. //
  1182. //  Fonctions spécialisées dans la gestion des fichiers CDDA
  1183.  
  1184. /// CDDA_AudioC/GetFileInfos()
  1185. /****** Class CDDA_AudioC/GetFileInfos **************************************
  1186. *
  1187. *   NAME
  1188. *   CDDA_AudioC::GetFileInfos -- Analyse un fichier CDDA
  1189. *
  1190. *   SYNOPSIS
  1191. *   Result = CDDA_AudioC::GetFileInfos()
  1192. *
  1193. *   bool CDDA_AudioC::GetFileInfos();
  1194. *
  1195. *   FUNCTION
  1196. *   Analyse le fichier afin de connaître le nombre d'échantillons. Ce nombre
  1197. *   est basé sur la taille du fichier.
  1198. *   La fonction analyse en outre un bloc pris dans le milieu du fichier afin
  1199. *   d'essayer de déterminer le format de ce fichier (MOTOROLA/INTEL).
  1200. *
  1201. *   RESULT
  1202. *   Result - FALSE en cas d'erreur (Erreur de lecture).
  1203. *
  1204. *   NOTES
  1205. *   Surdéfinition d'une fonction virtuelle
  1206. *
  1207. *   Les fichiers CDDA sont considérés comme étant en stéréo, avec des échan-
  1208. *   tillons codés sur 16 bits, et échantillonnés à 44100 Hz.
  1209. *   La discrimination entre les formats Motorola et Intel se base sur un test
  1210. *   empirique. Elle repose sur la moyenne des différences entre les échantil-
  1211. *   lons d'un bloc pris dans le milieu du fichier. Cette reconnaissance n'est
  1212. *   donc pas absolument fiable.
  1213. *
  1214. *   SEE ALSO
  1215. *   MAUD_AudioC::GetFileInfos()
  1216. *   AIFF_AudioC::GetFileInfos()
  1217. *   RAW_AudioC::GetFileInfos()
  1218. *   WAV_AudioC::GetFileInfos()
  1219. *
  1220. *****************************************************************************
  1221. *
  1222. */
  1223.  
  1224.  
  1225. int CDDA_AudioC::GetFileInfos()
  1226. {
  1227.     const int iNumSmpl   = 256*16;      // Nombre d'échantillons à examiner.
  1228.     const int iThreshold = 10000;       // Limite acceptée pour la moyenne. Au delà de cette limite,
  1229.                                         // on formule l'hypothèse que le fichier est au format INTEL.
  1230.     ULONG NumFrames = istr_roFileInfo.GetFileLength() >> 2;
  1231.  
  1232.     SetNumFrames(NumFrames);
  1233.  
  1234.     istr_roFileInfo.SetEncodingMode(STEREO);
  1235.     istr_roFileInfo.OverrideSettings(44100, 2);
  1236.  
  1237.     int       i, sum;
  1238.     WORD     *pSamples = NULL;
  1239.     LONG      iRead    = 0;
  1240.     int       iResult  = FALSE;
  1241.  
  1242.     SetAudioFormat(FORMAT_MOTOROLA_STEREO);         // Présumer que le fichier est au format Motorola.
  1243.  
  1244.     if (istr_roFileInfo.GetCDDAFmt() == 1)
  1245.     {
  1246.         SetFileType(AFT_CDDA);
  1247.         iResult = TRUE;
  1248.     }
  1249.     else if (istr_roFileInfo.GetCDDAFmt() == 2)
  1250.     {
  1251.         SetAudioFormat(FORMAT_INTEL_STEREO);
  1252.         SetFileType(AFT_CDDA_INTEL);
  1253.         iResult = TRUE;
  1254.     }
  1255.     else
  1256.     {
  1257.         // Ouvrir le fichier, puis charger un petit bloc d'échantillons dans un tampon pour analyse.
  1258.  
  1259.         if (OpenStream() == IOERR_NONE && (pSamples = new WORD[iNumSmpl * 2]) )
  1260.         {
  1261.             if (NewSeek(istr_bpFileHandle, NumFrames >> 1, OFFSET_BEGINING) >= 0
  1262.                 && (iRead = ::Read(istr_bpFileHandle, pSamples, iNumSmpl * 4) >> 1) )
  1263.             {
  1264.                 // Analyser le tampon.
  1265.                 // On calcule ici la somme des différences entre chaque echantillon.
  1266.                 // Si la moyenne de ces sommes est inférieure à une certaine limite,
  1267.                 // on fait l'hypothèse que le fichier est au format Motorola.
  1268.  
  1269.                 for (i = 2, sum = 0; i < iRead; i += 2)
  1270.                 {
  1271.                     int t = pSamples[i] - pSamples[i-2];
  1272.                     sum += (t < 0) ? -t : t;
  1273.                 }
  1274.  
  1275.                 int analyze = (sum * 2) / iRead;
  1276.  
  1277.                 if (analyze > iThreshold)
  1278.                 {
  1279.                     SetFileType(AFT_CDDA_INTEL);
  1280.                     SetAudioFormat(FORMAT_INTEL_STEREO);
  1281.                 }
  1282.                 iResult = TRUE;
  1283.             }
  1284.             CloseStream();
  1285.         }
  1286.         else
  1287.         {
  1288.             SetIoError(IOERR_DOS, ::IoErr());        // Erreur pendant la lecture du fichier.
  1289.         }
  1290.         delete [] pSamples;
  1291.     }
  1292.  
  1293.     return iResult;
  1294. }
  1295. ///
  1296.  
  1297. //----------------------------------------------------------------------------------------------------
  1298. //======================================== Classe WAV_AudioC =========================================
  1299. //----------------------------------------------------------------------------------------------------
  1300. //
  1301. //  Fonctions spécialisées dans la gestion des fichiers WAVE
  1302.  
  1303. /// Définitions
  1304.  
  1305. #define fmt_ID  MAKE_ID('f','m','t',' ')
  1306. #define data_ID MAKE_ID('d','a','t','a')
  1307.  
  1308. /* RIFF header */
  1309. struct RIFFHeader
  1310. {
  1311.     ULONG   rh_RIFF;            // RIFF
  1312.     ULONG   rh_Size;
  1313.     ULONG   rh_Format;          // WAVE
  1314. };
  1315.  
  1316.  
  1317. /* RIFF chunk */
  1318. struct RIFFChunk
  1319. {
  1320.     ULONG   rc_ID;
  1321.     ULONG   rc_Size;
  1322. };
  1323.  
  1324.  
  1325. struct WaveFormat
  1326. {
  1327.     WORD     wf_Format;             // WAVE_FORMAT_PCM
  1328.     WORD     wf_Channels;           // 1 = Mono, 2 = Stereo
  1329.     ULONG    wf_SamplesPerSec;      // Fréquence d'échantillonage.
  1330.     ULONG    wf_AvgBytesPerSec;     // Taux de transfert (nombre d'octets par seconde)
  1331.     WORD     wf_BlockAlign;         // Nombre d'octets à lire par sample.
  1332. };
  1333.  
  1334. /* wf_Format values */
  1335. #define WAVE_FORMAT_PCM     1
  1336.  
  1337. struct PCMData
  1338. {
  1339.     UWORD    pd_BitsPerSample;      // Nombre de bits par échantillons.
  1340. };
  1341.  
  1342. ///
  1343.  
  1344. /// WAV_AudioC::GetFileInfos()
  1345. /****** Class WAV_AudioC/GetFileInfos ***************************************
  1346. *
  1347. *   NAME
  1348. *   WAV_AudioC::GetFileInfos -- Analyse un fichier WAV.
  1349. *
  1350. *   SYNOPSIS
  1351. *   result = WAV_AudioC::GetFileInfos()
  1352. *
  1353. *   bool WAV_AudioC::GetFileInfos();
  1354. *
  1355. *   FUNCTION
  1356. *   Analyse un fichier WAV afin d'obtenir la fréquence d'échantillonage, le
  1357. *   nombre d'échantillons du fichier et le nombre de canaux.
  1358. *   Si le fichier possède plus de 2 canaux, ou si les échantillons ne sont
  1359. *   pas codés sur 16 bits, le fichier est rejeté.
  1360. *   De plus, ce fichier doit être au format MicroSoft PCM à l'exclusion de
  1361. *   tout autre.
  1362. *
  1363. *   RESULT
  1364. *   result - FALSE en cas d'erreur.
  1365. *
  1366. *   NOTES
  1367. *   Surdéfinition d'une fonction virtuelle
  1368. *
  1369. *   SEE ALSO
  1370. *   MAUD_AudioC::GetFileInfos()
  1371. *   AIFF_AudioC::GetFileInfos()
  1372. *   CDDA_AudioC::GetFileInfos()
  1373. *   RAW_AudioC::GetFileInfos()
  1374. *
  1375. *****************************************************************************
  1376. *
  1377. */
  1378.  
  1379.  
  1380. int WAV_AudioC::GetFileInfos()
  1381. {
  1382.     struct WAV_fmt {struct WaveFormat sWaveFormat;      // Format du bloc d'entête.
  1383.                     struct PCMData    sPCMData;
  1384.                    };
  1385.  
  1386.     int     iGotIt     = FALSE;
  1387.     ULONG   iChunkSize = 0;
  1388.     ULONG   iRead;
  1389.     WAV_fmt sWavFmt;
  1390.  
  1391.     if (OpenStream() == IOERR_NONE)
  1392.     {
  1393.         // Rechercher le chunk 'fmt '.
  1394.  
  1395.         if ( (iChunkSize = LocateChunk('fmt ')) == sizeof(WAV_fmt) )
  1396.         {
  1397.             // Lire le bloc de format.
  1398.  
  1399.             if ( (iRead = Read(istr_bpFileHandle, &sWavFmt, iChunkSize)) == iChunkSize)
  1400.             {
  1401.                 WORD  wav_Format      = _getword(sWavFmt.sWaveFormat.wf_Format);
  1402.                 WORD  wav_Channels    = _getword(sWavFmt.sWaveFormat.wf_Channels);
  1403.                 LONG  wav_SamplFreq   = _getlong(sWavFmt.sWaveFormat.wf_SamplesPerSec);
  1404.                 WORD  wav_BitsPerSmpl = _getword(sWavFmt.sPCMData.pd_BitsPerSample);
  1405.  
  1406.                 // Contrôler les données de l'entête.
  1407.  
  1408.                 if (   wav_Format == WAVE_FORMAT_PCM
  1409.                     && wav_Channels > 0
  1410.                     && wav_Channels < 3
  1411.                     && wav_BitsPerSmpl == 16)
  1412.                 {
  1413.                     // Rechercher le nombre d'échantillons.
  1414.  
  1415.                     istr_iChannelSize = LocateChunk('data') >> 1;     // 16 bits par échantillon.
  1416.                     if (wav_Channels == 2) istr_iChannelSize >>= 1;   // Mode stéréo.
  1417.  
  1418.                     if (istr_iChannelSize > 0)
  1419.                     {
  1420.                         SetNumFrames(istr_iChannelSize);
  1421.                         iGotIt = istr_roFileInfo.OverrideSettings(wav_SamplFreq, wav_Channels);
  1422.                         SetAudioFormat( (wav_Channels == 1) ? FORMAT_INTEL_MONO : FORMAT_INTEL_STEREO );
  1423.                         if (!iGotIt) SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  1424.                     }
  1425.                 }
  1426.             }
  1427.         }
  1428.         CloseStream();
  1429.     }
  1430.  
  1431.     // Si le format du fichier n'est pas supporté (ou si le fichier ne peut être ouvert),
  1432.     // placer les codes d'erreur et modifier le code de type de fichier.
  1433.  
  1434.     if (!iGotIt)
  1435.     {
  1436.         SetFileType(AFT_BAD_WAV);
  1437.         SetIoError(IOERR_INTERNAL, ERROR_OBJECT_WRONG_TYPE);
  1438.     }
  1439.  
  1440.     return iGotIt;
  1441. }
  1442. ///
  1443. /// WAV_AudioC::LocateChunk()
  1444. /****** Class WAV_AudioC/LocateChunk ****************************************
  1445. *
  1446. *   NAME
  1447. *   WAV_AudioC::LocateChunk -- Rechercher un chunk RIFF.
  1448. *
  1449. *   SYNOPSIS
  1450. *   Size = WAV_AudioC::LocateChunk(ChunkID)
  1451. *
  1452. *   ULONG WAV_AudioC::LocateChunk(ULONG);
  1453. *
  1454. *   FUNCTION
  1455. *   Recherche un chunk RIFF dans le fichier. Le fichier doit avoir été ouvert
  1456. *   au préalable.
  1457. *
  1458. *   INPUTS
  1459. *   ChunkID - Nom du chunk à trouver.
  1460. *
  1461. *   RESULT
  1462. *   Size - Taille du chunk, ou 0 en cas d'erreur.
  1463. *
  1464. *   NOTES
  1465. *   La fonction repositionne le pointeur de lecture juste après le chunk d'
  1466. *   entête (RIFFxxxxWAVE), puis saute tous les chunks rencontrés jusqu'à
  1467. *   trouver le chunk voulu ou la fin du fichier.
  1468. *
  1469. *   BUGS
  1470. *   La fonction utilise la longueur de bloc mentionnée dans les chunks pour
  1471. *   repositionner le pointeur de lecture sur le chunk suivant. Il n'est pas
  1472. *   évident que cette longueur corresponde toujours à la taille réelle du
  1473. *   chunk, ce qui peut causer des problèmes de gestion (puisque dès lors, la
  1474. *   fonction sera incapable de retrouver le chunk demandé).
  1475. *
  1476. *****************************************************************************
  1477. *
  1478. */
  1479.  
  1480.  
  1481. ULONG WAV_AudioC::LocateChunk(ULONG ChunkID)
  1482. {
  1483.     RIFFChunk sChunk;
  1484.     ULONG     iSize = 0;
  1485.     ULONG     iRead;
  1486.  
  1487.     // Sauter le bloc d'entête (déjà connu puisque le fichier a été identifié
  1488.     // comme étant un fichier RIFF-WAVE).
  1489.  
  1490.     if (NewSeek(istr_bpFileHandle, sizeof(RIFFHeader), OFFSET_BEGINING) >= 0)
  1491.     {
  1492.         while ( (iRead = ::Read(istr_bpFileHandle, &sChunk, sizeof(RIFFChunk))) > 0)
  1493.         {
  1494.             iSize = _getlong(sChunk.rc_Size);
  1495.  
  1496.             if (sChunk.rc_ID == ChunkID) return iSize;
  1497.             if (NewSeek(istr_bpFileHandle, iSize, OFFSET_CURRENT) < 0) break;
  1498.         }
  1499.     }
  1500.  
  1501.     return (0L);
  1502. }
  1503. ///
  1504. /// WAV_AudioC::SeekToAudio()
  1505. /****** Class WAV_AudioC/SeekToAudio ****************************************
  1506. *
  1507. *   NAME
  1508. *   WAV_AudioC::SeekToAudio -- Préparer la lecture du bloc audio.
  1509. *
  1510. *   SYNOPSIS
  1511. *   Result = WAV_AudioC::SeekToAudio()
  1512. *
  1513. *   bool WAV_AudioC::SeekToAudio();
  1514. *
  1515. *   FUNCTION
  1516. *   Positionne le pointeur de lecture au début du bloc de données audio.
  1517. *   Le fichier WAV doit avoir été ouvert et initialisé avant d'appeler cette
  1518. *   fonction.
  1519. *
  1520. *   RESULT
  1521. *   Result - FALSE en cas d'erreur.
  1522. *
  1523. *   NOTES
  1524. *   Surdéfinition d'une fonction virtuelle.
  1525. *
  1526. *   SEE ALSO
  1527. *   InputStreamC::SeekToAudio()
  1528. *   IFF_AudioC::SeekToAudio()
  1529. *
  1530. *****************************************************************************
  1531. *
  1532. */
  1533.  
  1534. int WAV_AudioC::SeekToAudio()
  1535. {
  1536.     return (LocateChunk('data') != 0);
  1537. }
  1538. ///
  1539.  
  1540.