1 /*-------------- Telecommunications & Signal Processing Lab ---------------
2                              McGill University
3 
4 Routine:
5   int AOsetDformat (const struct AO_FOpar *FO, AFILE *AFp[], int Nf)
6 
7 Purpose:
8   Determine a compatible output data format for the output file type
9 
10 Description:
11   This routine determines an output data format compatible with an output
12   file type.  If either is explicitly specified, that data format is used.
13   If the output data format is not specified, it is chosen to have the same or
14   greater precision as that of the input data formats.
15 
16   For use in error messages, the program name should be set using the routine
17   UTsetProg.
18 
19 Parameters:
20   <-  int AOsetFormat
21       Output code for the data format
22    -> const struct AO_FOpar *FO
23       Output file parameters.  The file type (FO->Ftype) can be FTW_UNDEF.
24       The data format (FO->DFormat.Format) can be FD_UNDEF.
25    -> const AFILE *AFp[]
26       Audio file pointers for the input files (Nf values)
27    -> int Nf
28       Number of input audio file pointers (can be zero)
29 
30 Author / revision:
31   P. Kabal  Copyright (C) 2003
32   $Revision: 1.1 $  $Date: 2003/05/12 23:52:13 $
33 
34 -------------------------------------------------------------------------*/
35 
36 #include <stdio.h>	/* FILENAME_MAX */
37 
38 #include <libtsp.h>		/* defines AFILE, used by AFpar.h */
39 #define AF_DATA_TYPE_NAMES
40 #define AF_OUTPUT_FILE_TYPE_NAMES
41 #include <libtsp/AFpar.h>
42 #include <AO.h>
43 
44 #define ROUTINE		"AOsetFormat"
45 #define PGM		((UTgetProg ())[0] == '\0' ? ROUTINE : UTgetProg ())
46 #define MAXV(a, b)	(((a) > (b)) ? (a) : (b))
47 
48 /* Resulting precision for mixed data formats */
49 /* 0 - undefined, 1 - 16-bit, 2 - 24-bit, 3 - 32-bit, 4 - float, 5 - double */
50 static const int Prec[NFD] = { 0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 1};
51 
52 /* Canonical data formats for each of the precisions */
53 static const int DfPrec[6] = {FD_UNDEF, FD_INT16, FD_INT24, FD_INT32,
54 			      FD_FLOAT32, FD_FLOAT64};
55 
56 static const int *
57 AO_Allow (int Ftype);
58 
59 
60 int
AOsetDformat(const struct AO_FOpar * FO,AFILE * AFp[],int Nf)61 AOsetDformat (const struct AO_FOpar *FO, AFILE *AFp[], int Nf)
62 
63 {
64   int i, Ftype, Dformat, Df;
65   const int *Allow;
66 
67 /*
68    Format   Ftype
69   defined   defined    Use the combination specified by the user, but give an
70                        error if the combination is unsupported.
71   defined   undefined  If the data format is text, use a noheader file
72                        type, otherwise use the file type determined from the
73 		       file extension.
74   undefined defined    Data format from input, modified by allowable output
75                        data formats for the given file type.
76   undefined undefined  Data format from input, output file type determined from
77                        the file extension.
78 */
79 
80   /* Set the output file type if not set */
81   Ftype = AOsetFtype (FO);
82   Allow = AO_Allow (Ftype);
83 
84   Dformat = FO->DFormat.Format;
85   if (Dformat == FD_UNDEF) {
86 
87 /* Data format not defined */
88     /* Choose the output data format based on the input data format
89        Data promotion rules
90        - convert to allowable data formats for the output file type
91        - for mixed input formats, find the resulting precision
92        - find the canonical data format for that precision
93     */
94     if (Nf <= 0)
95       Dformat = Allow[AO_DFORMATO_DEFAULT];
96     else
97       Dformat = Allow[AFp[0]->Format];
98 
99     for (i = 1; i < Nf; ++i) {
100       Df = Allow[AFp[i]->Format];
101       if (Df != Dformat)
102 	Dformat = DfPrec[MAXV (Prec[Df], Prec[Dformat])];
103     }
104   }
105 
106   else  {
107 
108 /* File type defined, data format now defined (perhaps by default) */
109     /* Check for compatibility of the data format and file type */
110     if (Dformat != Allow[Dformat])
111       UThalt (AOMF_DataFType, PGM, AF_DTN[Dformat], AF_FTWN[Ftype]);
112   }
113 
114   return Dformat;
115 }
116 
117 static const int *
AO_Allow(int Ftype)118 AO_Allow (int Ftype)
119 
120 {
121   const int *Allow;
122 
123 /* Conversion tables to allowable data formats for different file types */
124   static const int Allow_AU[NFD] = {
125     FD_UNDEF, FD_MULAW8, FD_ALAW8, FD_INT8, FD_INT8, FD_INT16, FD_INT24,
126     FD_INT32, FD_FLOAT32, FD_FLOAT64, FD_INT16
127   };
128   static const int Allow_WAVE[NFD] = {
129     FD_UNDEF, FD_MULAW8, FD_ALAW8, FD_UINT8, FD_UINT8, FD_INT16, FD_INT24,
130     FD_INT32, FD_FLOAT32, FD_FLOAT64, FD_INT16
131   };
132   static const int Allow_AIFF[NFD] = {
133     FD_UNDEF, FD_INT16, FD_INT16, FD_INT8, FD_INT8, FD_INT16, FD_INT24,
134     FD_INT32, FD_INT16, FD_INT16, FD_INT16
135   };
136   static const int Allow_AIFF_C[NFD] = {
137     FD_UNDEF, FD_MULAW8, FD_ALAW8, FD_INT8, FD_INT8, FD_INT16, FD_INT24,
138     FD_INT32, FD_FLOAT32, FD_FLOAT64, FD_INT16
139   };
140   static const int Allow_NH[NFD] = {
141     FD_UNDEF, FD_MULAW8, FD_ALAW8, FD_UINT8, FD_INT8, FD_INT16, FD_INT24,
142     FD_INT32, FD_FLOAT32, FD_FLOAT64, FD_TEXT
143   };
144 
145   switch (Ftype) {
146   case FTW_AU:
147     Allow = Allow_AU;
148     break;
149   case FTW_WAVE:
150   case FTW_WAVE_NOEX:
151     Allow = Allow_WAVE;
152     break;
153   case FTW_AIFF:
154     Allow = Allow_AIFF;
155     break;
156   case FTW_AIFF_C:
157     Allow = Allow_AIFF_C;
158     break;
159   case FTW_NH_EB:
160   case FTW_NH_EL:
161   case FTW_NH_NATIVE:
162   case FTW_NH_SWAP:
163     Allow = Allow_NH;
164     break;
165   default:
166     Allow = NULL;
167     UThalt ("%s: %s", PGM, AOM_InvFTypeC);
168   }
169 
170   return Allow;
171 }
172