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

  1.                           /**************************************************/
  2.                           /*                                                */
  3.                           /*                   Common.cpp                   */
  4.                           /*                                                */
  5.                           /*         Fonctions communes aux modules         */
  6.                           /*                                                */
  7.                           /**************************************************/
  8.  
  9. /*
  10. ** $Revision: 1.3 $
  11. ** $State: Exp $
  12. ** $Date: 1998/08/16 19:03:33 $
  13. **
  14. ** $Log: Common.cpp $
  15. ** Revision 1.3  1998/08/16 19:03:33  kakace
  16. ** Version Beta3+
  17. **
  18. ** Revision 1.2  1998/08/02 15:16:59  kakace
  19. ** Fonctionnement OK (Layer 1/2 + Stereo/JStereo)
  20. **
  21. ** Revision 1.1  1998/07/24 14:26:50  kakace
  22. ** Automatic global CheckIn
  23. **
  24. ** Revision 1.26  1998/07/24 14:14:22  kakace
  25. ** Version intermédiaire (CheckIn global)
  26. **
  27. ** Revision 1.24  1998/07/02 15:51:55  kakace
  28. ** Automatic global CheckIn
  29. **
  30. */
  31.  
  32. //----------------------------------------------------------------------------------------------------
  33.  
  34. /// Includes
  35.  
  36. #ifndef  _INCLUDE_STDLIB_H
  37. #include <stdlib.h>
  38. #endif
  39.  
  40. #ifndef  _INCLUDE_IOSTREAM_H
  41. #include <iostream.h>
  42. #endif
  43.  
  44. #ifndef  _INCLUDE_IOMANIP_H
  45. #include <iomanip.h>
  46. #endif
  47.  
  48. #ifndef  DOS_DOS_H
  49. #include <dos/dos.h>
  50. #endif
  51.  
  52. #ifndef  _PEGASECOND_HPP
  53. #include "PegaseCond.hpp"
  54. #endif
  55.  
  56. #ifndef  _PEGASE_HPP
  57. #include "Pegase.hpp"
  58. #endif
  59.  
  60. #ifndef  _FILEINFOS_CLASS_HPP
  61. #include "FileInfosC.hpp"
  62. #endif
  63.  
  64. #ifndef  _INPUTSTREAM_CLASS_HPP
  65. #include "InputStreamC.hpp"
  66. #endif
  67.  
  68. #ifndef  _MEMORY_HPP
  69. #include "memory.hpp"
  70. #endif
  71.  
  72. #ifndef  _COMMON_HPP
  73. #include "Common.hpp"
  74. #endif
  75.  
  76. #ifndef  _ENCODERCONFIG_CLASS_HPP
  77. #include "EncoderConfigC.hpp"
  78. #endif
  79.  
  80. #ifndef  _CODER_CLASS_HPP
  81. #include "CoderC.hpp"
  82. #endif
  83.  
  84. #ifndef  CLASS_DISPLAY_HPP
  85. #include "Display.hpp"
  86. #endif
  87.  
  88. ///
  89.  
  90.  
  91. #define  CDDA_MULTIPLE  2352            // Longueur des blocs des fichiers CDDA
  92.  
  93. #define CATCOMP_NUMBERS
  94. #ifndef  PEGASE_H
  95. #include "Pegase.h"
  96. #endif
  97.  
  98.  
  99. //----------------------------------------------------------------------------------------------------
  100. //======================================== Prototypes privés =========================================
  101. //----------------------------------------------------------------------------------------------------
  102.  
  103. e_AudioTypes     IdentifyInputFile(FileInfosC &roFileInfo);
  104. e_IoErrors       InitFileInfos(FileInfosC &roFileInfo);
  105. e_FileListErrors IdentifyFile(AnchorPath *pAnchor, char *cPath, PegaseConfigC &roCfg);
  106.  
  107. void InitTimer();
  108. LONG GetElapsedTime();
  109.  
  110.  
  111. //----------------------------------------------------------------------------------------------------
  112. //============================================ Fonctions =============================================
  113. //----------------------------------------------------------------------------------------------------
  114.  
  115. /// ReadFileList()
  116. //----------------------------------------------------------------------------------------------------
  117. //========================================== ReadFileList() ==========================================
  118. //----------------------------------------------------------------------------------------------------
  119. /****** Common/ReadFileList *************************************************
  120. *
  121. *   NAME
  122. *   ReadFileList -- Initialiser la liste chaînée des fichier à traiter.
  123. *
  124. *   SYNOPSIS
  125. *   error = ReadFileList(cFrom)
  126. *
  127. *   bool ReadFileList(const char *);
  128. *
  129. *   FUNCTION
  130. *   Examine la source passée en argument, puis analyse les fichiers qu'elle
  131. *   contient. Lorsqu'un fichier audio est détecté, il est ajouté à la liste
  132. *   globale (sa position étant déterminée par son type).
  133. *   Les fichiers non-audio, ou dont le format n'est pas supporté sont
  134. *   ignorés.
  135. *
  136. *   La source peut être un nom du fichier, un nom de répertoire ou un motif
  137. *   de recherche. Lorsqu'il s'agit d'un répertoire, tous les fichiers de ce
  138. *   répertoire sont analysés, mais tous les sous-répertoires sont ignorés.
  139. *
  140. *   INPUTS
  141. *   cFrom    - Nom du répertoire à examiner, nom du fichier à charger, ou
  142. *              motif de recherche. S'il s'agit d'un nom de répertoire, tous
  143. *              les fichiers contenus dans ce répertoire sont analysés, et
  144. *              les éventuels sous-répertoires sont ignorés.
  145. *              Un pointeur nul ou une chaîne nulle sont acceptés, la fonction
  146. *              retournant alors "NO_NAME_GIVEN".
  147. *
  148. *   RESULT
  149. *   error - Code de l'erreur rencontrée.
  150. *           La présence d'une erreur ne signifie pas qu'aucun fichier n'a été
  151. *           ajouté à la liste globale.
  152. *
  153. *   NOTES
  154. *   Cette fonction utilise les fonctions DOS MatchFirst()/MatchNext() et
  155. *   MatchEnd().
  156. *   Le tampon alloué dynamiquement pour recevoir la copie du nom complet du
  157. *   répertoire parent peut voir sa taille augmenter lorsque c'est nécessaire
  158. *   (gestion dynamique).
  159. *
  160. *   Si la fonction vient à manquer de mémoire, l'examen des sources est
  161. *   immédiatement stoppée. Par contre, une erreur I/O sur l'un des fichiers
  162. *   n'interdit pas l'examen des autres fichiers audio.
  163. *
  164. *   BUGS
  165. *   Voir les Autodocs concernant MatchFirst().
  166. *   La fonction ignore les SoftLinks.
  167. *
  168. *   SEE ALSO
  169. *   class FileInfosC, class PegaseConfigC
  170. *
  171. *****************************************************************************
  172. *
  173. */
  174.  
  175. #define INITIAL_PATH_BUFF_SIZE   256            // Taille originale par défaut du tampon dynamique
  176.                                                 // utilisé pour la recopie du nom du répertoire.
  177. #define INCREASE_BUFF_SIZE_VALUE  64            // Incrément pour l'augmentation de la taille du
  178.                                                 // tampon dynamique.
  179.  
  180. e_FileListErrors ReadFileList(PegaseConfigC &roGlobalCfg, ULONG iIndex)
  181. {
  182.     CMatch           match;
  183.     LONG             iMatch;
  184.     e_FileListErrors iError = NO_ERROR;         // Code d'erreur à retourner.
  185.     int              EnableDoDir = TRUE;        // Drapeau permettant d'entrer dans un répertoire.
  186.     AnchorPath      *pAnchor;
  187.  
  188.     // Le nom du répertoire parent retourné est le nom complet du chemin d'accès (après
  189.     // résolution éventuelle de toute assignation).
  190.     // La taille du tampon utilisé pour la recopie de ce nom de répertoire est dynamique.
  191.     // Autrement dit, la fonction est capable d'allouer un tampon plus grand que celui
  192.     // disponible lorsque c'est nécessaire.
  193.  
  194.     ULONG iPathBuffSize = INITIAL_PATH_BUFF_SIZE;
  195.     CString cPath;
  196.  
  197.     // Avorter si le nom du fichier/répertoire/motif est incorrect ou s'il n'y a plus assez
  198.     // de mémoire pour allouer le tampon dynamique.
  199.  
  200.     STRING cFrom = roGlobalCfg[iIndex];       // Rechercher la source (fichier ou répertoire).
  201.  
  202.     if (cFrom == NULL || *cFrom == 0)                 return (NO_NAME_GIVEN);
  203.  
  204.     // pAnchor->ap_BreakBits = 0;
  205.     // pAnchor->ap_Flags     = 0;
  206.     // pAnchor->ap_Strlen    = 0;
  207.  
  208.     // Rechercher les fichiers audios (source inspiré de l'Amiga Guru Book p.456)
  209.     // Si l'utilisateur a choisi un nom de répertoire, entrer dans ce répertoire.
  210.     // Passée la première entrée, les répertoires sont ignorés.
  211.  
  212.     for (iMatch = match.First(cFrom); iMatch == 0; iMatch = match.Next() )
  213.     {
  214.         pAnchor = match;
  215.  
  216.         // Si la source passée en argument correspond à un répertoire, y entrer. Dans les autres
  217.         // cas, les répertoires sont ignorés.
  218.  
  219.         if (pAnchor->ap_Info.fib_DirEntryType >= 0
  220.             && pAnchor->ap_Info.fib_DirEntryType != ST_SOFTLINK
  221.             && EnableDoDir != FALSE)
  222.         {
  223.             pAnchor->ap_Flags |= APF_DODIR;                     // Entrer dans le répertoire.
  224.         }
  225.         else
  226.         {
  227.             pAnchor->ap_Flags &= ~APF_DIDDIR;
  228.  
  229.             // Examiner le fichier trouvé, à condition que ce ne soit pas un SoftLink.
  230.  
  231.             if (pAnchor->ap_Info.fib_DirEntryType < 0)          // Ignore les SoftLinks
  232.             {
  233.                 int success;
  234.  
  235.                 // Obtenir le nom complet du répertoire parent.
  236.  
  237.                 if ( (success = DOSLib::NameFromLock(pAnchor->ap_Current->an_Lock, cPath)) )
  238.                 {
  239.                     IdentifyFile(pAnchor, cPath, roGlobalCfg);
  240.                 }
  241.             }
  242.         }
  243.         EnableDoDir = FALSE;                        // Interdire d'entrer dans les prochains répertoire.
  244.         if (iError == NO_MEMORY) break;             // Avorter immédiatement si la mémoire manque.
  245.     }
  246.  
  247.     // Libérer les ressources locales.
  248.  
  249.     if (iMatch != ERROR_NO_MORE_ENTRIES && iError == NO_ERROR)
  250.         iError = MATCHING_ERROR;                    // Cette erreur n'est pas prioritaire.
  251.  
  252.     return iError;
  253. }
  254. ///
  255. /// IdentifyFile()
  256. //----------------------------------------------------------------------------------------------------
  257. //========================================== IdentifyFile() ==========================================
  258. //----------------------------------------------------------------------------------------------------
  259. /****** Common/IdentifyFile *************************************************
  260. *
  261. *   NAME
  262. *   IdentifyFile -- Identifie un fichier.
  263. *
  264. *   SYNOPSIS
  265. *   Erreur = IdentifyFile(pAnchor, cPath)
  266. *
  267. *   e_FileListErrors IdentifyFile(AnchorPath *, char *);
  268. *
  269. *   FUNCTION
  270. *   Identifie le fichier actuellement pointé par la structure AnchorPath.
  271. *   La fonction initialise et chaîne un objet FileInfos décrivant ce fichier
  272. *   s'il s'agit d'un fichier audio. Dans le cas contraire, le fichier est
  273. *   simplement ignoré.
  274. *
  275. *   Si Pegase a été lancé depuis le Shell, la fonction rend compte de l'
  276. *   analyse du fichier.
  277. *
  278. *   14.8.99 :
  279. *   Si le fichier d'entrée arrive par un PIPE, le format est automatiquement
  280. *   choisi comme étant CDDA. Le format des échantillons peut être forcé en
  281. *   utilisant les drapeaux INTEL ou MOTOROLA sur la ligne de commande (le
  282. *   format MOTOROLA étant le format par défaut).
  283. *
  284. *   INPUTS
  285. *   pAnchor  - Structure AnchorPath.
  286. *   cPath    - Chemin d'accès au fichier.
  287. *
  288. *   RESULT
  289. *   Erreur - Code d'erreur (NO_ERROR ou NO_MEMORY)
  290. *
  291. *****************************************************************************
  292. *
  293. */
  294.  
  295.  
  296. e_FileListErrors IdentifyFile(AnchorPath *pAnchor, char *cPath, PegaseConfigC &roCfg)
  297. {
  298.     e_FileListErrors iError = NO_ERROR;
  299.     e_AudioTypes     iAudioType = AFT_UNKNOWN;
  300.     e_IoErrors       iIOErr = IOERR_NONE;
  301.     FileInfosC      *poNode;
  302.  
  303.     if ( (poNode = new FileInfosC(pAnchor->ap_Info.fib_FileName, cPath, roCfg)) )
  304.     {
  305.         poNode->SetFileLength(pAnchor->ap_Info.fib_Size);
  306.  
  307.         display->out() << GetString(MSG_ANALYSING_TXT) << " \"" << pAnchor->ap_Info.fib_FileName << "\" : ";
  308.  
  309.         if (roCfg.GetCDDAFmt() == 0)
  310.         {
  311.             // Examiner le fichier rencontré.
  312.  
  313.             iAudioType = IdentifyInputFile(*poNode);
  314.             iIOErr     = poNode->GetIoError();
  315.  
  316.             // Si le fichier a été identifié comme un fichier audio, et s'il n'y a pas eu
  317.             // d'erreurs, initialiser les informations le concernant.
  318.  
  319.             if (iAudioType < AFT_NOT_AUDIO && iIOErr == IOERR_NONE)
  320.             {
  321.                 iIOErr = InitFileInfos(*poNode);
  322.                 iAudioType = poNode->GetFileType();
  323.             }
  324.         }
  325.         else    // MOTOROLA/INTEL ==> CDDA.
  326.         {
  327.             if (roCfg.GetCDDAFmt() == 2)
  328.             {
  329.                 iAudioType = AFT_CDDA_INTEL;
  330.             }
  331.             else
  332.             {
  333.                 iAudioType = AFT_CDDA;
  334.                 roCfg.SetCDDAFmt(1);            // Format MOTOROLA par défaut.
  335.             }
  336.  
  337.             poNode->SetFileType(iAudioType);
  338.             iIOErr = InitFileInfos(*poNode);
  339.         }
  340.  
  341.         // Traiter les erreurs, ou chaîner le fichier à la liste globale s'il n'y en a pas eu.
  342.  
  343.         if (iIOErr != IOERR_NONE && iIOErr != IOERR_WARN || iAudioType >= AFT_NOT_AUDIO)
  344.         {
  345.             if (iIOErr == IOERR_INTERNAL && iAudioType < AFT_NOT_AUDIO)
  346.             {
  347.                 display->out() << GetString(MSG_UNSUPPORTED_FREQUENCY_ERROR);
  348.             }
  349.             else
  350.             {
  351.                 STRING s;
  352.  
  353.                 switch(iAudioType)
  354.                 {
  355.                     case AFT_NOT_AUDIO:
  356.                         s = GetString(MSG_NOT_AN_AUDIO_FILE_ERROR);
  357.                         break;
  358.  
  359.                     case AFT_BAD_AIFF:
  360.                         s = GetString(MSG_BAD_AIFF_ERROR);
  361.                         break;
  362.  
  363.                     case AFT_BAD_MAUD:
  364.                         s = GetString(MSG_BAD_MAUD_ERROR);
  365.                         break;
  366.  
  367.                     case AFT_BAD_WAV:
  368.                         s = GetString(MSG_BAD_WAVE_ERROR);
  369.                         break;
  370.  
  371.                     default:
  372.                         s = GetString(MSG_READ_ERROR);
  373.                         break;
  374.                 }
  375.                 display->out() << s << endl;
  376.             }
  377.  
  378.             if (iIOErr == IOERR_NO_MEMORY) iError = NO_MEMORY;
  379.  
  380.             delete poNode;              // Détruire l'objet associé au fichier courant en cas d'erreur.
  381.         }
  382.         else
  383.         {
  384.             roCfg.Enqueue(poNode);
  385.             display->out() << poNode->GetAudioName() << endl;
  386.  
  387.             if (iIOErr == IOERR_WARN && poNode->GetError2() == ERROR_BAD_HUNK)
  388.                 display->out() << GetString(MSG_WARN_BADIFF_SIZE) << endl;
  389.  
  390.             poNode->SetIoError(IOERR_NONE);
  391.         }
  392.     }
  393.     else iError = NO_MEMORY;
  394.  
  395.     return iError;
  396. }
  397. ///
  398. /// RequestFileList()
  399. //----------------------------------------------------------------------------------------------------
  400. //======================================== RequestFileList() =========================================
  401. //----------------------------------------------------------------------------------------------------
  402. /****** Common/RequestFileList **********************************************
  403. *
  404. *   NAME
  405. *   RequestFileList -- Obtenir une liste de fichiers.
  406. *
  407. *   SYNOPSIS
  408. *   RequestFileList(cDefPath)
  409. *
  410. *   void RequestFileList(STRING);
  411. *
  412. *   FUNCTION
  413. *   Ouvre un requester de fichier permettant à l'utilisateur de choisir les
  414. *   fichiers à encoder.
  415. *   La fonction crée un tableau de pointeurs, chacun d'eux adressant un
  416. *   chemin d'accès correspondant à un fichier. Cela permet d'émuler le
  417. *   tableau retourné par ReadArgs() lors de l'examen de la ligne de commande.
  418. *
  419. *   INPUTS
  420. *   cDefPath - Chemin d'accès par défaut ou NULL.
  421. *
  422. *   NOTES
  423. *   · La position du requester, de même que ses dimensions, ne sont pas
  424. *     modifiables (codées dans le programme lui-même). Voir le tableau
  425. *     s_Tags[].
  426. *
  427. *   · Cette fonction pourrait éventuellement tirer parti des nouveautés des
  428. *     versions 38+ de l'asl.library
  429. *
  430. *****************************************************************************
  431. *
  432. */
  433.  
  434. extern CPegaseArgs goPegaseArgs;
  435.  
  436. void RequestFileList()
  437. {
  438.     // Tags initiaux pour l'ouverture du requester.
  439.  
  440.     static struct TagItem s_Tags[] =
  441.     {
  442.                     {ASLFR_Flags1, FRF_DOMULTISELECT|FRF_DOPATTERNS},
  443.                     {ASLFR_Flags2, FRF_REJECTICONS},
  444.                     {TAG_DONE, NULL}
  445.     };
  446.  
  447.     CFileRequest Req;
  448.     FileRequester *fileReq;
  449.  
  450.     if (Req.Init(s_Tags))
  451.     {
  452.         if ( (fileReq = Req.Request(ASLFR_TitleText, GetString(MSG_FILEREQUEST_TITLE),
  453.                                     ASLFR_InitialPattern, GlobalConfig.GetPattern(),
  454.                                     ASLFR_InitialLeftEdge, *goPegaseArgs.pa_FR_XPos,
  455.                                     ASLFR_InitialTopEdge, *goPegaseArgs.pa_FR_YPos,
  456.                                     ASLFR_InitialWidth, *goPegaseArgs.pa_FR_Width,
  457.                                     ASLFR_InitialHeight, *goPegaseArgs.pa_FR_Height,
  458.                                     (goPegaseArgs.pa_DefSource ? ASLFR_InitialDrawer : TAG_DONE), goPegaseArgs.pa_DefSource,
  459.                                     TAG_DONE)) )
  460.         {
  461.             char **file;
  462.             ULONG  path_length = 0;
  463.             ULONG  num_entries = fileReq->fr_NumArgs;
  464.             char  *path        = fileReq->fr_Drawer;
  465.             CString buff;
  466.  
  467.             if (path == NULL || *path == 0)  path = NULL;   // Ignorer un nom de répertoire nul.
  468.  
  469.             // Prendre en compte la sélection multiple le cas échéant.
  470.  
  471.             if (num_entries)
  472.             {
  473.                 file = (char **) &fileReq->fr_ArgList->wa_Name;
  474.             }
  475.             else
  476.             {
  477.                 num_entries = 1;
  478.                 file = (char **) &fileReq->fr_File;
  479.             }
  480.  
  481.             // Allouer le tableau de pointeurs, puis copier les chaînes obtenues.
  482.  
  483.             for (int entry_index = 0; entry_index < num_entries; ++entry_index, file += 2)
  484.             {
  485.                 buff = path;
  486.                 DOSLib::AddPart(buff, *file);
  487.                 GlobalConfig.Add(buff);
  488.             }
  489.         }
  490.     }
  491. }
  492. ///
  493.  
  494. //----------------------------------------------------------------------------------------------------
  495.  
  496. /// IdentifyInputFile()
  497. /****** Common.cpp/IdentifyInputFile ****************************************
  498. *
  499. *   NAME
  500. *   IdentifyInputFile -- Identifier un fichier audio.
  501. *
  502. *   SYNOPSIS
  503. *   type = IdentifyInputFile(roFileInfo)
  504. *
  505. *   e_AudioTypes IdentifyInputFile(FileInfosC);
  506. *
  507. *   FUNCTION
  508. *   Cette fonction se charge d'identifier le fichier dont le nom est passé
  509. *   en paramètre. Cette reconnaîssance se fonde sur le contenu des tous
  510. *   premiers octets du fichier, ou sur l'extension du nom de fichier lorsqu'
  511. *   une reconnaîssance plus fine n'est pas possible.
  512. *
  513. *   Actuellement, les fichiers suivants sont traîtés :
  514. *       IFF_AIFF : Fichier IFF
  515. *       IFF_MAUD : Fichier IFF
  516. *       RIFF     : Fichier WAVE
  517. *       #?.raw   : Données audio brutes
  518. *       #?.pcm   : Données audio brutes
  519. *       #?.cdda  : Fichier CDDA
  520. *       0xE310   : Fichier icône (rejeté)
  521. *       0x03F3   : Fichier exécutable (rejeté)
  522. *       'GIF8'   : Fichier GIF (rejeté)
  523. *       0xFFD8.. : Fichier JPEG (rejeté)
  524. *
  525. *   Les fichiers dont le format n'est pas reconnu immédiatement, ou les
  526. *   fichiers RAW sont promus au type CDDA si leur taille est un multiple
  527. *   entier de 2352.
  528. *
  529. *   INPUTS
  530. *   roFileInfo - Objet FileInfos décrivant le fichier.
  531. *
  532. *   RESULT
  533. *   type - Type du fichier. AFT_UNKNOWN est retourné lorsque le type du
  534. *       fichier n'a pu être déterminé, ou lorsqu'une erreur s'est produite.
  535. *       Dans ce dernier cas, roFileInfos.GetIoError() permet d'obtenir un
  536. *       supplément d'information sur cette erreur.
  537. *       Le type AFT_DEFAULT est similaire au type AFT_PCM, à la différence
  538. *       que le fichier n'a pas été identifié comme tel de manière certaine.
  539. *
  540. *   NOTES
  541. *   Cette fonction crée un certain nombre de tableaux sur la pile. S'
  542. *   assurer qu'elle est appelée avec une taille de pile suffisante.
  543. *
  544. *****************************************************************************
  545. *
  546. */
  547.  
  548. static const char PCM_EXTENSION[]  = "#?.pcm";
  549. static const char RAW_EXTENSION[]  = "#?.raw";
  550. static const char CDDA_EXTENSION[] = "#?.cdda";
  551.  
  552.  
  553. e_AudioTypes
  554. IdentifyInputFile(FileInfosC &roFileInfo)
  555. {
  556.     const ULONG BUFFSIZE = 32;
  557.  
  558.     CFile    FH;
  559.     CLock    NewDir;
  560.     BPTR     bpOldDir;
  561.     ULONG    a_iIdentBuff[BUFFSIZE];
  562.  
  563.     e_AudioTypes iType;
  564.     STRING cFileName = roFileInfo.NodeName();
  565.     ULONG iFL = roFileInfo.GetFileLength();
  566.  
  567.     extern int CheckExtension(STRING cFileName, STRING cExtension, ULONG iExtLen);
  568.  
  569.     // Si le fichier a une taille impaire, il ne peut pas s'agir d'un fichier audio.
  570.  
  571.     if ( (iFL & 1) != 0 || iFL < 4)
  572.     {
  573.         iType = AFT_NOT_AUDIO;
  574.     }
  575.     else
  576.     {   // Changer le répertoire courant pour s'assurer qu'on adresse le bon fichier.
  577.  
  578.         iType = AFT_UNKNOWN;
  579.  
  580.         if ( (NewDir.Lock(roFileInfo.GetPathName(), CLock::READ)) != 0)
  581.         {
  582.             bpOldDir = DOSLib::CurrentDir(NewDir);
  583.  
  584.             // Ouvrir le fichier, et examiner son type.
  585.  
  586.             if ( (FH.Open(cFileName, CFile::OLDFILE)) != NULL)
  587.             {
  588.                 if (FH.Read(a_iIdentBuff, BUFFSIZE * 4) > 4)
  589.                 {
  590.                     if (a_iIdentBuff[0] == 'FORM')          // Fichier IFF. Examiner le type exact.
  591.                     {
  592.                         switch(a_iIdentBuff[2])
  593.                         {
  594.                             case 'AIFF':
  595.                                 iType = AFT_AIFF;           // AIFF.
  596.                                 break;
  597.  
  598.                             case 'MAUD':
  599.                                 iType = AFT_MAUD;           // MAUD.
  600.                                 break;
  601.  
  602.                             default:
  603.                                 iType = AFT_NOT_AUDIO;      // Non supporté (image par exemple).
  604.                         }
  605.                     }
  606.                     if (a_iIdentBuff[0] == 'RIFF')      iType = AFT_WAV;
  607.  
  608.                     // Reconnaissance basée sur l'extension du nom de fichier (.pcm, .raw)
  609.  
  610.                     if (CheckExtension(cFileName, PCM_EXTENSION, sizeof(PCM_EXTENSION)-1) != FALSE ||
  611.                         CheckExtension(cFileName, RAW_EXTENSION, sizeof(RAW_EXTENSION)-1) != FALSE)
  612.                         iType = AFT_PCM;
  613.  
  614.                     // Les fichiers CDDA doivent avoir une longueur multiple de 2352.
  615.  
  616.                     if (CheckExtension(cFileName, CDDA_EXTENSION, sizeof(CDDA_EXTENSION)-1) != FALSE &&
  617.                         roFileInfo.GetFileLength() % CDDA_MULTIPLE == 0)
  618.                         iType = AFT_CDDA;
  619.  
  620.                     // Types spéciaux... (forcément rejetés).
  621.  
  622.                     ULONG hdr = a_iIdentBuff[0];
  623.  
  624.                     if (  (hdr >> 16) == 0xE310         // Fichier icône.
  625.                         || hdr == 0x3F3                 // Fichier exécutable.
  626.                         || hdr == 'GIF8'                // Fichier GIF.
  627.                         || hdr == 0xFFD8FFE0            // Fichier JPEG (?)
  628.                        )
  629.                     {
  630.                         iType = AFT_NOT_AUDIO;
  631.                     }
  632.                 }
  633.                 else roFileInfo.SetIoError(IOERR_READ, DOSLib::IoErr());
  634.             }
  635.             else roFileInfo.SetIoError(IOERR_OPEN, DOSLib::IoErr());
  636.  
  637.             DOSLib::CurrentDir(bpOldDir);         // Restaurer le répertoire original
  638.         }
  639.         else roFileInfo.SetIoError(IOERR_DOS, DOSLib::IoErr());
  640.  
  641.         // Si le type du fichier est inconnu, on part du principe que c'est un fichier RAW...
  642.  
  643.         if (iType == AFT_UNKNOWN) iType = AFT_DEFAULT;
  644.  
  645.         // Promouvoir les types RAW/PCM en type CDDA si la longueur du fichier fait
  646.         // penser à un fichier CDDA.
  647.  
  648.         if ( (iType == AFT_PCM || iType == AFT_DEFAULT) && (roFileInfo.GetFileLength() % CDDA_MULTIPLE) == 0)
  649.             iType = AFT_CDDA;
  650.     }
  651.  
  652.     roFileInfo.SetFileType(iType);          // Définir le type de fichier audio.
  653.     return (iType);
  654. }
  655.  
  656.  
  657. // Fonction privée remplaçant avantageusement ParsePattern/MatchPattern
  658. // Retourne TRUE si le fichier possède bien l'extension passée en argument.
  659.  
  660. int CheckExtension(STRING cFileName, STRING cExtension, ULONG iExtLen)
  661. {
  662.     return DOSLib::MatchPatternNoCase(cFileName, cExtension);
  663. }
  664. ///
  665. /// InitFileInfos()
  666. /****** Common.cpp/InitFileInfos ********************************************
  667. *
  668. *   NAME
  669. *   InitFileInfos -- Obtenir les infos du fichier.
  670. *
  671. *   SYNOPSIS
  672. *   Error = InitFileInfos(roFileInfo)
  673. *
  674. *   e_IoErrors InitFileInfos(FileInfosC &);
  675. *
  676. *   FUNCTION
  677. *   Examine le fichier afin d'obtenir les informations concernant le nombre
  678. *   d'échantillons, la fréquence d'échantillonage, etc.
  679. *
  680. *   INPUTS
  681. *   roFileInfo - Informations sur le fichier courant.
  682. *
  683. *   RESULT
  684. *   Error - Code d'erreur.
  685. *
  686. *   NOTES
  687. *   Cette fonction crée un objet InputStream afin d'analyser le fichier audio
  688. *   (fréquence d'échantillonage, etc).
  689. *
  690. *   Le type du fichier audio peut être modifié par cette fonction (notament
  691. *   lorsque le fichier n'est pas dans un format correct conformément au
  692. *   type attendu).
  693. *
  694. *   SEE ALSO
  695. *   Class InputStreamC
  696. *
  697. *****************************************************************************
  698. *
  699. */
  700.  
  701.  
  702. e_IoErrors
  703. InitFileInfos(FileInfosC &roFileInfo)
  704. {
  705.     InputStreamC *poInput = NULL;               // Handle
  706.  
  707.     poInput = CreateAudioC(roFileInfo);
  708.  
  709.     // Rechercher les informations sur le fichier.
  710.  
  711.     if (poInput == NULL)    roFileInfo.SetIoError(IOERR_NO_MEMORY);
  712.     else                    poInput->GetFileInfos();
  713.  
  714.     // Libérer l'objet InputStream étant donné qu'il n'a servi qu'à obtenir certaines informations
  715.     // sur le fichier.
  716.  
  717.     delete poInput;
  718.  
  719.     return roFileInfo.GetIoError();
  720. }
  721. ///
  722. /// CreateAudioC()
  723. /****** Common/CreateAudioC *************************************************
  724. *
  725. *   NAME
  726. *   CreateAudioC -- Créer un objet AudioC
  727. *
  728. *   SYNOPSIS
  729. *   AudioObject = CreateAudioC(roFileInfo)
  730. *
  731. *   InputStreamC * CreateAudioC(FileInfosC &);
  732. *
  733. *   FUNCTION
  734. *   Crée un fichier AudioC correspondant au fichier à traiter.
  735. *
  736. *   INPUTS
  737. *   roFileInfo - Informations concernant le fichier à traiter.
  738. *
  739. *   RESULT
  740. *   AudioObject - Objet AudioC ou NULL en cas de problème.
  741. *
  742. *****************************************************************************
  743. *
  744. */
  745.  
  746.  
  747. InputStreamC *CreateAudioC(FileInfosC &roFileInfo)
  748. {
  749.     InputStreamC *poInput = NULL;
  750.  
  751.     switch(roFileInfo.GetFileType())
  752.     {
  753.         // Fichiers RAW/PCM/CDDA/UNKNOWN
  754.  
  755.         case AFT_DEFAULT:
  756.         case AFT_PCM:
  757.         {
  758.             poInput = new RAW_AudioC(roFileInfo);
  759.             break;
  760.         }
  761.  
  762.         case AFT_CDDA:
  763.         case AFT_CDDA_INTEL:
  764.             poInput = new CDDA_AudioC(roFileInfo);
  765.             break;
  766.  
  767.         // Fichiers IFF AIFF/MAUD
  768.  
  769.         case AFT_AIFF:
  770.             poInput = new AIFF_AudioC(roFileInfo);
  771.             break;
  772.  
  773.         case AFT_MAUD:
  774.             poInput = new MAUD_AudioC(roFileInfo);
  775.             break;
  776.  
  777.         // Fichiers RIFF-WAV
  778.  
  779.         case AFT_WAV:
  780.             poInput = new WAV_AudioC(roFileInfo);
  781.             break;
  782.  
  783.         default:
  784.             break;
  785.     }
  786.  
  787.     return poInput;
  788. }
  789. ///
  790.  
  791. //----------------------------------------------------------------------------------------------------
  792. //=========================================== EncodeFile() ===========================================
  793. //----------------------------------------------------------------------------------------------------
  794.  
  795. int EncodeFile(FileInfosC &roFileInfos)
  796. {
  797.     e_EncoderST iStatus = ESTAT_NOTREADY;
  798.  
  799.     STRING sResultString = NULL;
  800.     int    done = TRUE;
  801.  
  802.     // Créer un objet Layer pour l'encodage du fichier courant.
  803.  
  804.     e_Layer iLayerType = roFileInfos.GetLayer();
  805.     CoderC *poEncoder = NULL;
  806.  
  807.     switch (iLayerType)
  808.     {
  809.         case LAYER_I:
  810.             poEncoder = new CoderL1C(roFileInfos);
  811.             break;
  812.  
  813.         case LAYER_II:
  814.             poEncoder = new CoderL2C(roFileInfos);
  815.             break;
  816.     }
  817.  
  818.     if (poEncoder != NULL) iStatus = poEncoder->GetEncoderStatus();
  819.  
  820.     // Si l'encodeur est prêt, commencer l'encodage.
  821.  
  822.     if (iStatus == ESTAT_READY)
  823.     {
  824.         InitTimer();
  825.  
  826.         //-----------------------------
  827.         //===== BOUCLE PRINCIPALE =====
  828.         //-----------------------------
  829.  
  830.         int stop = 0;
  831.         display->ResetAnimVal();
  832.  
  833.         while (poEncoder->GetAudio() && stop == 0)
  834.         {
  835.             if (!poEncoder->Encode()) break;
  836.  
  837.             stop = display->UpdateProgression(poEncoder->GetProgression(), &roFileInfos);
  838.             if (stop & SIGBREAKF_CTRL_D) done = FALSE;
  839.         }
  840.  
  841.         // Afficher les messages d'erreurs éventuels.
  842.  
  843.         e_IoErrors IOErr = roFileInfos.GetIoError();
  844.         ULONG      Err2  = roFileInfos.GetError2();
  845.  
  846.         if (IOErr == IOERR_INTERNAL && Err2 == ERROR_BREAK)             sResultString = GetString(MSG_BREAK_TXT);
  847.         else if (IOErr == IOERR_WARN && Err2 == ERROR_NO_MORE_ENTRIES)
  848.         {
  849.             LONG iNumSecs = GetElapsedTime();
  850.  
  851.             // Afficher le temps écoulé pendant l'encodage.
  852.  
  853.             if (iNumSecs < 0)
  854.             {
  855.                 display->out() << "\n" << GetString(MSG_NO_TIMER_ERRORTXT) << "\n" << endl;
  856.             }
  857.             else
  858.             {
  859.                 div_t temp;
  860.                 int s;
  861.  
  862.                 temp = div(iNumSecs, 60);
  863.                 s = temp.rem;
  864.                 temp = div(temp.quot, 60);
  865.  
  866.                 display->out() << "\n" << GetString(MSG_ELAPSED_TIME_TXT) << " : ";
  867.                 display->out().fill('0');
  868.                 display->out().width(2);
  869.                 display->out() << temp.quot << ":";
  870.                 display->out().width(2);
  871.                 display->out() << temp.rem << ":";
  872.                 display->out().width(2);
  873.                 display->out() << s;
  874.  
  875.                 u_Time t = roFileInfos.GetTime();
  876.                 if (t.iTime != 0x5858)
  877.                 {
  878.                     int duration = t.sTime.bMinutes * 60 + t.sTime.bSecondes;
  879.                     int elapsed  = (temp.quot * 60 + temp.rem) * 60 + s;
  880.                     double r = (double) elapsed / duration;
  881.                     int prec = display->out().precision(2);
  882.  
  883.                     display->out() << "  (ratio = " << r << ":1)";
  884.                     display->out().precision(prec);
  885.                 }
  886.                 display->out() << endl;
  887.             }
  888.  
  889.             display->out() << GetString(MSG_DONE_TXT) << endl;
  890.         }
  891.         else if (IOErr == IOERR_NO_MEMORY) sResultString = GetString(MSG_OUT_OF_MEMORY_ERROR);
  892.         else if (IOErr != IOERR_NONE)      sResultString = GetString(MSG_STREAM_ERROR);
  893.     }
  894.  
  895.     // Traiter les codes d'erreur de l'encodeur.
  896.  
  897.     if (poEncoder)
  898.     {
  899.         e_EncErrCodes iErrCode = poEncoder->GetSecondaryError();
  900.         iStatus = poEncoder->GetEncoderStatus();
  901.  
  902.         if (iStatus == ESTAT_NOTSUPPORTED)
  903.         {
  904.             // Actuellement, la seule erreur possible est : ERR_BAD_FREQUENCY.
  905.  
  906.             sResultString = GetString(MSG_UNSUPPORTED_FREQUENCY_ERROR);
  907.         }
  908.         else if (iStatus == ESTAT_NOTREADY)
  909.         {
  910.             switch (iErrCode)
  911.             {
  912.                 case ERR_NOT_INITIALIZED:
  913.                     sResultString = GetString(MSG_ENCODER_NOT_READY_ERROR);
  914.                     break;
  915.  
  916.                 case ERR_ISTREAM_FAILURE:
  917.                     sResultString = GetString(MSG_ISTREAM_ERROR);
  918.                     break;
  919.  
  920.                 default:
  921.                     break;
  922.             }
  923.         }
  924.         else if (iStatus == ESTAT_IOERROR)
  925.         {
  926.             switch (iErrCode)
  927.             {
  928.                 case ERR_OPEN_OSTREAM:
  929.                     sResultString = GetString(MSG_OPEN_OSTREAM_ERROR);
  930.                     break;
  931.  
  932.                 case ERR_SEEK_OSTREAM:
  933.                     sResultString = GetString(MSG_SEEK_OSTREAM_ERROR);
  934.                     break;
  935.  
  936.                 case ERR_WRITE_OSTREAM:
  937.                     sResultString = GetString(MSG_WRITE_OSTREAM_ERROR);
  938.                     break;
  939.  
  940.                 case ERR_CLOSE_OSTREAM:
  941.                     sResultString = GetString(MSG_CLOSE_OSTREAM_ERROR);
  942.                     break;
  943.  
  944.                 default:
  945.                     break;
  946.             }
  947.         }
  948.         else if (iStatus == ESTAT_NOMEMORY)
  949.         {
  950.             // Actuellement, la seule erreur possible est : ERR_INTERNAL_BUFFERS
  951.  
  952.             sResultString = GetString(MSG_OUT_OF_MEMORY_ERROR);
  953.         }
  954.     }
  955.     else
  956.     {
  957.         sResultString = GetString(MSG_OUT_OF_MEMORY_ERROR);
  958.     }
  959.  
  960.     if (sResultString) display->PrintErrorMsg(sResultString);
  961.  
  962.     // Libérer les ressources allouées.
  963.  
  964.     delete poEncoder;
  965.     return done;
  966. }
  967.  
  968.  
  969. //----------------------------------------------------------------------------------------------------
  970. //============================================== Timer ===============================================
  971. //----------------------------------------------------------------------------------------------------
  972.  
  973. /// Définitions pour l'utilisation du Timer
  974.  
  975. #ifndef  DEVICES_TIMER_H
  976. #include <devices/timer.h>
  977. #endif
  978.  
  979. #ifndef  CLIB_TIMER_PROTOS_H
  980. #include <clib/timer_protos.h>
  981. #endif
  982.  
  983. extern "C"{
  984. struct Library *TimerBase = NULL;
  985. };
  986.  
  987. timerequest TimerIO;
  988. timeval     Time1;
  989.  
  990. ///
  991. /// InitTimer()
  992. /****** Common/InitTimer ****************************************************
  993. *
  994. *   NAME
  995. *   InitTimer -- Initialiser le Timer.
  996. *
  997. *   SYNOPSIS
  998. *   InitTimer()
  999. *
  1000. *   void InitTimer();
  1001. *
  1002. *   FUNCTION
  1003. *   Ouvre le timer.device, puis note l'heure courante afin de pouvoir cal-
  1004. *   culer ultérieurement le temps de calcul de l'encodeur.
  1005. *
  1006. *   SEE ALSO
  1007. *   GetElapsedTime(), EncodeFile()
  1008. *
  1009. *****************************************************************************
  1010. *
  1011. */
  1012.  
  1013.  
  1014. void InitTimer()
  1015. {
  1016.     if (!::OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *) &TimerIO, 0))
  1017.     {
  1018.         TimerBase = (Library *) TimerIO.tr_node.io_Device;
  1019.         ::GetSysTime(&Time1);
  1020.     }
  1021. }
  1022. ///
  1023. /// GetElapsedTime()
  1024. /****** Common/GetElapsedTime ***********************************************
  1025. *
  1026. *   NAME
  1027. *   GetElapsedTime -- Calculer une durée.
  1028. *
  1029. *   SYNOPSIS
  1030. *   NumSecs = GetElapsedTime()
  1031. *
  1032. *   LONG GetElapsedTime();
  1033. *
  1034. *   FUNCTION
  1035. *   Calcule le temps écoulé depuis l'appel de la fonction InitTimer().
  1036. *   A l'issue de ce calcul, le timer.device est automatiquement libéré.
  1037. *
  1038. *   RESULT
  1039. *   NumSecs - Nombre de secondes écoulées, ou -1 en cas d'erreur.
  1040. *
  1041. *   SEE ALSO
  1042. *   InitTimer(), EncodeFile()
  1043. *
  1044. *****************************************************************************
  1045. *
  1046. */
  1047.  
  1048.  
  1049. LONG GetElapsedTime()
  1050. {
  1051.     timeval Time2;
  1052.  
  1053.     if (TimerBase)
  1054.     {
  1055.         ::GetSysTime(&Time2);
  1056.         ::SubTime(&Time2, &Time1);
  1057.         ::CloseDevice((struct IORequest *) &TimerIO);
  1058.  
  1059.         return Time2.tv_secs;
  1060.     }
  1061.     else return (-1);
  1062. }
  1063. ///
  1064.  
  1065. //----------------------------------------------------------------------------------------------------
  1066. //====================================== Gestion de la mémoire =======================================
  1067. //----------------------------------------------------------------------------------------------------
  1068.  
  1069. /// AllocAlignedBuffer()
  1070. //----------------------------------------------------------------------------------------------------
  1071. //======================================== AllocAlignedBuffer ========================================
  1072. //----------------------------------------------------------------------------------------------------
  1073. //
  1074. //  Allouer un tampon de la taille indiquée, aligné sur une adresse multiple de 16.
  1075. //
  1076. //  ALGO : Exec retourne toujours une adresse multiple de 8, donc il suffit d'ajouter 8 à l'adresse
  1077. //      retournée lorsqu'elle n'est pas multiple de 16 pour obtenir un pointeur sur un bloc aligné.
  1078. //      Une entête est insérée avant le bloc de façon à garder une trace du pointeur original (qui
  1079. //      devra être passé à FreeBuffer() tôt ou tard).
  1080.  
  1081. #ifdef __PPC__
  1082. #define ALIGN   32
  1083. #else
  1084. #define ALIGN   16
  1085. #endif
  1086.  
  1087.  
  1088. void *AllocAlignedBuffer(ULONG size)
  1089. {
  1090.     LONG *p;
  1091.     LONG *pa;
  1092.  
  1093.     if ( (p = (LONG *) AllocBuffer(size + (ALIGN+8)) ) != NULL)
  1094.     {
  1095.         pa = (LONG *) ( ((LONG)p + (ALIGN+7)) & (~(ALIGN-1)) );
  1096.                                                             // pa = Pointeur aligné.
  1097.         *(pa - 1) = (LONG)pa - (LONG)p;                     // Pour contrôle (0 ou 8).
  1098.         *(pa - 2) = (LONG)p;                                // Adresse à passer à FreeBuffer()
  1099.  
  1100.         return (pa);
  1101.     }
  1102.  
  1103.     return (NULL);
  1104. }
  1105. ///
  1106. /// FreeAlignedBuffer()
  1107. //----------------------------------------------------------------------------------------------------
  1108. //======================================== FreeAlignedBuffer =========================================
  1109. //----------------------------------------------------------------------------------------------------
  1110. //
  1111. //  Libérer un bloc aligné sur une adresse multiple de 16.
  1112. //  L'assertion permet de vérifier la conformité du pointeur présent dans l'entête de bloc (ceci
  1113. //  assure que l'adresse transmise en argument correspond bien à un bloc aligné, et que le pointeur
  1114. //  à passer à FreeBuffer() n'a pas été écrasé par mégarde).
  1115.  
  1116. void FreeAlignedBuffer(void *buffaddr)
  1117. {
  1118.     FreeBuffer((void *) *((LONG *)buffaddr - 2));
  1119. }
  1120. ///
  1121.  
  1122.