00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <stdlib.h>
00034 #include <string.h>
00035
00036 #include "uti.h"
00037 #include "assert.h"
00038 #include "caudiox.hpp"
00039 #include "wrkbuff.h"
00040
00041
00042
00043 #define INFO_MARKS "Marks"
00044
00045
00046
00047 #define TXHLINE_MAXLEN 4096
00048
00049 #define DEF_TXTCOMMENT 100
00050
00051 #define DEF_TXTCOLUMNS 20
00052
00053
00054 #define TXH_FIRM "# TXH"
00055 #define TXH_VMAYOR 1
00056 #define TXH_VMINOR 0
00057
00058
00059
00060 LONG txtReadAllInfo( FILE *f, KVStrList &info, Mark1DList &marks,
00061 const CHAR *txhName, BOOL verify_fformat )
00062 {
00063 int tl;
00064 WRKBUFF(TXHLINE_MAXLEN);
00065
00066 if (verify_fformat) {
00067 xfgetln(_wrkbuff,TXHLINE_MAXLEN,f,&tl);
00068 cdie_beep(tl,"CAudioFile: line to long in %s (1)", txhName);
00069 size_t len = strlen(TXH_FIRM);
00070 if ((strlen(_wrkbuff)<=len)||(strncmp(_wrkbuff,TXH_FIRM,len)))
00071 die_beep("CAudioFile: not a valid audio-info file (%s)",txhName);
00072 int major, minor;
00073 sscanf(_wrkbuff+len,"%i.%i",&major, &minor);
00074 if (TXH_VMAYOR*100+TXH_VMINOR<major*100+minor)
00075 die_beep("CAudioFile: invalid version in %s (%i.%i>%i.%i)",
00076 txhName, major, minor, TXH_VMAYOR, TXH_VMINOR);
00077 }
00078
00079 LONG line = 0;
00080 enum { GET_ENTRY, GET_MULTI} mode = GET_ENTRY;
00081 String name, val;
00082
00083 while (xfgetln_filt(_wrkbuff,TXHLINE_MAXLEN,f,TRUE,2,FALSE,&tl)) {
00084 line++;
00085 cdie_beep(tl,"CAudioFile: line to long in %s (%ld)", txhName, line);
00086 if (*_wrkbuff=='\0') continue;
00087
00088
00089 if (*_wrkbuff=='}') {
00090 cdie_beep((mode!=GET_MULTI),"CAudioFile: invalid line in %s (%ld)", txhName, line);
00091 info.add(name,val);
00092 mode = GET_ENTRY;
00093 continue;
00094 }
00095
00096 if (mode==GET_MULTI) { val+="\n"; val+=_wrkbuff; continue; }
00097
00098 char *s=strchr(_wrkbuff,'=');
00099 if (!s) { name=_wrkbuff; val=""; }
00100 else { name=String(_wrkbuff,(size_t)(s-_wrkbuff)); val=(s+1); }
00101 cdie_beep(!name.length(),"CAudioFile: invalid line in %s (%ld)", txhName, line);
00102
00103 if (!strcmp(name,INFO_MARKS)) {
00104 if (!strcmp(val,"{}")) continue;
00105 cdie_beep(strcmp(val,"{"), "CAudioFile: invalid line in %s (%ld)", txhName, line);
00106 marks.finput(f,FALSE,txhName,line,_wrkbuff,TXHLINE_MAXLEN,'}');
00107 continue;
00108 }
00109
00110 if (!strcmp(name,INFO_SAMPLES)) {
00111 cdie_beep(val!="{", "CAudioFile: invalid line in %s (%ld)", txhName, line);
00112 WRKBUFF_FREE();
00113 return line;
00114 }
00115
00116
00117 if (!strcmp(val,"{}")) val="";
00118 if (!strcmp(val,"{")) { mode=GET_MULTI; val=""; }
00119 else info.add(name,val);
00120 }
00121 cdie_beep(mode==GET_MULTI, "CAudioFile: unspected EOF in %s (%ld)", txhName, line);
00122
00123 WRKBUFF_FREE();
00124
00125 if (!line) return -1;
00126 else return 0;
00127 }
00128
00129
00130
00131 VOID hdrRead( CAudioFile *fa, const CHAR *txhName )
00132 {
00133 FILE* f;
00134 LONG b;
00135
00136 f = xfopen(txhName,"r");
00137
00138 b=txtReadAllInfo(f,fa->info(), fa->marks(), txhName, TRUE );
00139 cdie_beep(b!=0,"CAudioFile: sample data (%s) not allowed in TXH files",
00140 INFO_SAMPLES);
00141
00142 xfclose(f);
00143 }
00144
00145
00146
00147
00148
00149 VOID writeField( FILE* f, const CHAR* s )
00150 {
00151 size_t len;
00152
00153 if (!s) return;
00154 len = strlen(s);
00155 if (!len) return;
00156
00157 if (strchr(s,'\n')) {
00158 fprintf(f,"{\n");
00159 fwrite(s,1,len,f);
00160 fprintf(f,"\n}\n\n");
00161 return;
00162 }
00163
00164 if (strcspn(s," \t")==len) fprintf(f,"%s\n",s);
00165 else fprintf(f,"\"%s\"\n",s);
00166 }
00167
00168
00169
00170 VOID CAudioFile::txhLoad( const CHAR *mode )
00171 {
00172 FILE* f;
00173 const char * txhName = myOpts.val(CAUDIO_TXHNAME);
00174
00175 const char *tmode = (mode[0] && mode[1]) ? mode+1 : mode;
00176 f = fopen(txhName,"r");
00177 if (f) fclose(f);
00178
00179 txhUpdatable = TRUE;
00180 switch (*tmode) {
00181 case 'r':
00182 txhUpdatable = FALSE;
00183 if (f || (tmode!=mode)) hdrRead(this,txhName);
00184 break;
00185 case 'w':
00186 myInfo.add(CAUDIO_NSAMPLES,(LONG)0);
00187 break;
00188 case 'm':
00189 if (f || (tmode!=mode)) hdrRead(this,txhName);
00190 else myInfo.add(CAUDIO_NSAMPLES,(LONG)0);
00191 break;
00192 case 'M':
00193 if (f || (tmode!=mode)) hdrRead(this,txhName);
00194 else myInfo.add(CAUDIO_NSAMPLES,(LONG)0);
00195 f = fopen(txhName,"r+b");
00196 if (f) fclose(f); else txhUpdatable=FALSE;
00197 break;
00198 case 'a':
00199 if (f) hdrRead(this,txhName);
00200 else myInfo.add(CAUDIO_NSAMPLES,(LONG)0);
00201 break;
00202 default:
00203 die_beep("CAudioFile: invalid open() mode (%c)",*tmode);
00204 }
00205 }
00206
00207
00208
00209 VOID CAudioFile::txtWriteAllInfo( FILE *f, BOOL force_nsamp )
00210 {
00211 Lix p;
00212 String s;
00213 WRKBUFF(50);
00214
00215 if (!myInfo.contains(CAUDIO_NSAMPLES) && force_nsamp) {
00216 sprintf(_wrkbuff,CAUDIO_NSAMPLES " = %ld",(long)getNSamples()); fprintf(f,"%s\n",_wrkbuff);
00217 }
00218 if (!myInfo.contains(CAUDIO_SRATE)) {
00219 sprintf(_wrkbuff,CAUDIO_SRATE " = %g",(double)getSRate()); fprintf(f,"%s\n",_wrkbuff);
00220 }
00221 if (!myInfo.contains(CAUDIO_SAMPTYPE)) {
00222 sprintf(_wrkbuff,CAUDIO_SAMPTYPE" = %s",getSampType_a()); fprintf(f,"%s\n",_wrkbuff);
00223 }
00224 if (!myInfo.contains(CAUDIO_NCHAN)) {
00225 sprintf(_wrkbuff,CAUDIO_NCHAN " = %g",(double)getNChan()); fprintf(f,"%s\n",_wrkbuff);
00226 }
00227 if (!myInfo.contains(CAUDIO_BIGENDIAN)) {
00228 sprintf(_wrkbuff,CAUDIO_BIGENDIAN " = %s",getBigEndian()?"yes":"no"); fprintf(f,"%s\n",_wrkbuff);
00229 }
00230
00231 for (p=myInfo.first(); p!=0; p=myInfo.next(p)) {
00232 fprintf(f,"%s = ",(const char *)myInfo.itemkey(p));
00233 writeField(f,myInfo.itemval(p));
00234 }
00235
00236 if (myMarks.length()>0) {
00237 fprintf(f,"%s = {\n",INFO_MARKS);
00238 myMarks.foutput(f,TRUE,FALSE,FALSE);
00239 fprintf(f,"}\n");
00240 }
00241 WRKBUFF_FREE();
00242 }
00243
00244
00245
00246 VOID CAudioFile::txhWrite( VOID )
00247 {
00248 const char * txhName = myOpts.val(CAUDIO_TXHNAME);
00249 String s;
00250
00251
00252
00253 FILE *f = xfopen(txhName,"wb");
00254
00255 fprintf(f,"%s %i.%i - AhoLab\n\n",TXH_FIRM,TXH_VMAYOR,TXH_VMINOR);
00256
00257 txtWriteAllInfo(f,FALSE);
00258
00259 xfclose(f);
00260 }
00261
00262
00263
00264 BOOL CAudioFile::openFromTxt( const CHAR *fname, FILE *f, const KVStrList &Opts )
00265 {
00266 Mark1DList mrk;
00267 KVStrList inf;
00268 KVStrList opt(Opts);
00269 LONG line=txtReadAllInfo(f,inf,mrk,"file",FALSE);
00270
00271 if (inf.contains(CAUDIO_SRATE)) opt.add(CAUDIO_SRATE,inf.val(CAUDIO_SRATE));
00272 if (inf.contains(CAUDIO_SAMPTYPE)) opt.add(CAUDIO_SAMPTYPE,inf.val(CAUDIO_SAMPTYPE));
00273 if (inf.contains(CAUDIO_NCHAN)) opt.add(CAUDIO_NCHAN,inf.val(CAUDIO_NCHAN));
00274 if (inf.contains(CAUDIO_BIGENDIAN)) opt.add(CAUDIO_BIGENDIAN,inf.val(CAUDIO_BIGENDIAN));
00275
00276 open(fname,"w",opt);
00277
00278 myInfo = inf;
00279 myMarks = mrk;
00280
00281 if (line<=0) { WRKBUFF_FREE(); return FALSE; }
00282
00283 int tl;
00284
00285 WRKBUFF(TXHLINE_MAXLEN);
00286 short int si;
00287 double d;
00288 INT stype;
00289
00290 stype=getSampType();
00291
00292 while (xfgetln_filt(_wrkbuff,TXHLINE_MAXLEN,f,TRUE,0,FALSE,&tl)) {
00293 line++;
00294
00295 cdie_beep(tl,"CAudioFile: line to long in file (%ld)", line);
00296 CHAR *s=strtok(_wrkbuff," \t");
00297
00298 if (!s) continue;
00299 if (*s=='\0') continue;
00300
00301
00302 if (*s=='}') { WRKBUFF_FREE(); return TRUE; }
00303
00304 while (s) {
00305 if (stype==SAMPTYPE_PCM16) {
00306 cdie_beep(str2si(s,&si),"CAudioFile: invalid PCM16 sample value (%s)",s);
00307 setNoCh((INT16)si);
00308 }
00309 else if (stype==SAMPTYPE_PCM8U) {
00310 cdie_beep(str2si(s,&si),"CAudioFile: invalid PCM8U sample value (%s)",s);
00311 setNoCh((INT16)((si-128)<<8));
00312 }
00313 else if ((stype==SAMPTYPE_FLOAT32)||(stype==SAMPTYPE_FLOAT64)) {
00314 cdie_beep(str2d(s,&d),"CAudioFile: invalid FLOAT32 sample value (%s)",s);
00315 setNoCh(d);
00316 }
00317 else die_beep("CAudioFile: sample type %s not supported from txt file",
00318 getSampType_a());
00319 s=strtok(NULL," \t");
00320 }
00321 }
00322
00323 WRKBUFF_FREE();
00324
00325 return FALSE;
00326 }
00327
00328
00329
00330 BOOL CAudioFile::openFromTxt( const CHAR *fname, FILE *f,
00331 const CHAR* options, ... )
00332 {
00333 va_list argptr;
00334 va_start(argptr, options);
00335 BOOL b=openFromTxt(fname,f,options,argptr);
00336 va_end(argptr);
00337
00338 return b;
00339 }
00340
00341
00342
00343 BOOL CAudioFile::openFromTxt( const CHAR *fname, FILE *f,
00344 const CHAR* options, va_list argptr )
00345 {
00346 KVStrList tmp(options,"=", argptr);
00347
00348 return openFromTxt(fname,f,tmp);
00349 }
00350
00351
00352
00353 VOID CAudioFile::writeToTxt( FILE *f )
00354 {
00355 LONG whence, i, j, n;
00356 INT nch;
00357 LONG cols;
00358
00359 txtWriteAllInfo(f,TRUE);
00360
00361 whence = myOpts.lval(CAUDIO_TXTCOMMENT,DEF_TXTCOMMENT);
00362 cols = myOpts.lval(CAUDIO_TXTCOLUMNS,DEF_TXTCOLUMNS);
00363
00364 fprintf(f,INFO_SAMPLES " = {\n");
00365 n = getNSamples();
00366 nch = getNChan();
00367 j=whence;
00368 INT stype = getSampType();
00369 INT16 i16;
00370 DOUBLE d;
00371 LONG opos=getPos();
00372 setPos(0);
00373 LONG nn=n*nch;
00374
00375 for (i=0; i<nn; i++) {
00376 switch (stype) {
00377 case SAMPTYPE_PCM8U: getNoCh(i16); fprintf(f,"%4d",(int)((i16>>8)+128)); break;
00378 case SAMPTYPE_PCM16: getNoCh(i16); fprintf(f,"%6d",(int)i16); break;
00379 case SAMPTYPE_FLOAT32:
00380 case SAMPTYPE_FLOAT64: getNoCh(d); fprintf(f,"%g",(double)d); break;
00381 default:
00382 die_beep("CAudioFile: sample type %s not supported for txt file",
00383 getSampType_a());
00384 }
00385
00386 INT r=(INT)((i+1)%nch);
00387 if (!r) {
00388 if (whence && (j==whence)) { fprintf(f, " ; %ld",(long)(i/nch)); j=0; }
00389 j++;
00390 fprintf(f,"\n");
00391 }
00392 else {
00393 fprintf(f," ");
00394
00395
00396
00397 }
00398 }
00399
00400 fprintf(f,"}\n");
00401 setPos(opos);
00402 }
00403
00404