libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmAudLabelFile.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmLinkedHeap.h"
  10. #include "cmFile.h"
  11. #include "cmAudLabelFile.h"
  12. cmAlfH_t cmAlfNullHandle = cmSTATIC_NULL_HANDLE;
  13. typedef struct cmAlfRecd_str
  14. {
  15. cmAlfLabel_t r;
  16. struct cmAlfRecd_str* link;
  17. } cmAlfRecd_t;
  18. typedef struct
  19. {
  20. cmErr_t err;
  21. cmLHeapH_t lH;
  22. cmFileH_t fH;
  23. cmAlfRecd_t* list;
  24. int cnt;
  25. } cmAlf_t;
  26. cmAlf_t* _cmAlfHandleToPtr( cmAlfH_t h )
  27. {
  28. cmAlf_t* p = (cmAlf_t*)h.h;
  29. assert( p != NULL );
  30. return p;
  31. }
  32. cmAlfRC_t _cmAlfFree( cmAlf_t* p )
  33. {
  34. cmAlfRC_t rc = kOkAlfRC;
  35. cmLHeapDestroy(&p->lH);
  36. cmMemPtrFree(&p);
  37. return rc;
  38. }
  39. cmAlfRC_t cmAudLabelFileAlloc( cmCtx_t* ctx, cmAlfH_t* hp )
  40. {
  41. cmAlfRC_t rc;
  42. if((rc = cmAudLabelFileFree(hp)) != kOkAlfRC )
  43. return rc;
  44. cmAlf_t* p = cmMemAllocZ(cmAlf_t,1);
  45. cmErrSetup(&p->err,&ctx->rpt,"Audio Label File");
  46. if(!cmLHeapIsValid( p->lH = cmLHeapCreate(1024,ctx)))
  47. {
  48. cmErrMsg(&p->err,kLHeapFailAlfRC,"Linked heap create failed.");
  49. goto errLabel;
  50. }
  51. hp->h = p;
  52. errLabel:
  53. return rc;
  54. }
  55. cmAlfRC_t cmAudLabelFileAllocOpen( cmCtx_t* ctx, cmAlfH_t* hp, const cmChar_t* fn )
  56. {
  57. cmAlfRC_t rc;
  58. if((rc = cmAudLabelFileAlloc(ctx,hp)) != kOkAlfRC)
  59. return rc;
  60. return cmAudLabelFileOpen(*hp,fn);
  61. }
  62. cmAlfRC_t cmAudLabelFileFree( cmAlfH_t* hp )
  63. {
  64. cmAlfRC_t rc = kOkAlfRC;
  65. if( hp == NULL || cmAudLabelFileIsValid(*hp)==false )
  66. return kOkAlfRC;
  67. cmAlf_t* p = _cmAlfHandleToPtr(*hp);
  68. if((rc = _cmAlfFree(p)) != kOkAlfRC )
  69. return rc;
  70. hp->h = NULL;
  71. return rc;
  72. }
  73. bool cmAudLabelFileIsValid( cmAlfH_t h )
  74. { return h.h != NULL; }
  75. void _cmAlfInsert( cmAlf_t* p, cmReal_t begSecs, cmReal_t endSecs, const cmChar_t* label )
  76. {
  77. cmAlfRecd_t* np = p->list;
  78. cmAlfRecd_t* pp = NULL;
  79. cmAlfRecd_t* ip = cmLhAllocZ(p->lH,cmAlfRecd_t,1);
  80. ip->r.begSecs = begSecs;
  81. ip->r.endSecs = endSecs;
  82. ip->r.label = label==NULL || strlen(label)==0 ? NULL : cmLhAllocStr(p->lH,label);
  83. // set np to the next recd and
  84. // set pp to the prev recd
  85. while(np != NULL )
  86. {
  87. if( np->r.begSecs > begSecs )
  88. break;
  89. pp = np;
  90. np = np->link;
  91. }
  92. ip->link = np;
  93. // if the new recd is first on the list
  94. if( pp == NULL )
  95. p->list = ip;
  96. else
  97. pp->link = ip;
  98. // incr the recd count
  99. ++p->cnt;
  100. }
  101. // remove the record just after pp
  102. void _cmAlfRemove( cmAlf_t* p, cmAlfRecd_t* pp )
  103. {
  104. // if the list is already empty
  105. if( p->list == NULL )
  106. return;
  107. // if the first recd should be removed
  108. if( pp == NULL )
  109. {
  110. p->list = p->list->link;
  111. }
  112. else
  113. {
  114. // if pp points to the last recd
  115. if( pp->link == NULL )
  116. return;
  117. // remove pp->link from the list
  118. pp->link = pp->link->link;
  119. }
  120. assert( p->cnt != 0 );
  121. --p->cnt;
  122. }
  123. cmAlfRC_t cmAudLabelFileOpen( cmAlfH_t h, const cmChar_t* fn )
  124. {
  125. cmAlfRC_t rc = kOkAlfRC;
  126. cmAlf_t* p = _cmAlfHandleToPtr(h);
  127. cmChar_t* lineBuf = NULL;
  128. unsigned lineBufByteCnt = 0;
  129. unsigned line = 1;
  130. cmFileH_t fH = cmFileNullHandle;
  131. // open the label file
  132. if( cmFileOpen(&fH,fn,kReadFileFl,p->err.rpt) != kOkFileRC )
  133. {
  134. rc = cmErrMsg(&p->err,kFileFailAlfRC,"The audio label file '%s' could not be openend.",cmStringNullGuard(fn));
  135. goto errLabel;
  136. }
  137. // read each line
  138. while( cmFileGetLineAuto(fH,&lineBuf,&lineBufByteCnt) == kOkFileRC )
  139. {
  140. cmReal_t begSecs;
  141. cmReal_t endSecs;
  142. cmChar_t* label = NULL;
  143. cmChar_t* begPtr = lineBuf;
  144. cmChar_t* endPtr = NULL;
  145. // parse the start time in seconds
  146. errno = 0;
  147. begSecs = strtod(begPtr,&endPtr);
  148. if( errno != 0 )
  149. return cmErrMsg(&p->err,kSyntaxErrAlfRC,"Begin time conversion error on line %i in '%s'.",line,cmFileName(fH));
  150. // parse the end time in seconds
  151. begPtr = endPtr;
  152. endSecs = strtod(begPtr,&endPtr);
  153. if( errno != 0 )
  154. return cmErrMsg(&p->err,kSyntaxErrAlfRC,"End time conversion error on line %i in '%s'.",line,cmFileName(fH));
  155. label = endPtr;
  156. // eat any leading white space off the label
  157. while( *label )
  158. {
  159. if( isspace(*label) )
  160. ++label;
  161. else
  162. break;
  163. }
  164. // trim trailing space and '\n' from the label.
  165. int i = strlen(label)-1;
  166. for(; i>=0; --i)
  167. {
  168. if( isspace(label[i]) )
  169. label[i]=0;
  170. else
  171. break;
  172. }
  173. // if the label does not exist
  174. if( strlen(label)==0 )
  175. label = NULL;
  176. // insert a new recd
  177. _cmAlfInsert(p,begSecs,endSecs,label);
  178. ++line;
  179. }
  180. cmMemPtrFree(&lineBuf);
  181. if( cmFileClose(&fH) != kOkFileRC )
  182. rc = cmErrMsg(&p->err,kFileFailAlfRC,"The audio label file close failed.");
  183. errLabel:
  184. return rc;
  185. }
  186. cmAlfRC_t cmAudLabelFileInsert( cmAlfH_t h, cmReal_t begSecs, cmReal_t endSecs, const cmChar_t* label )
  187. {
  188. cmAlfRC_t rc = kOkAlfRC;
  189. cmAlf_t* p = _cmAlfHandleToPtr(h);
  190. _cmAlfInsert(p,begSecs,endSecs,label);
  191. return rc;
  192. }
  193. unsigned cmAudLabelFileCount( cmAlfH_t h )
  194. {
  195. cmAlf_t* p = _cmAlfHandleToPtr(h);
  196. return p->cnt;
  197. }
  198. const cmAlfLabel_t* cmAudLabelFileLabel( cmAlfH_t h, unsigned idx )
  199. {
  200. cmAlf_t* p = _cmAlfHandleToPtr(h);
  201. cmAlfRecd_t* lp = p->list;
  202. unsigned i;
  203. for(i=0; lp!=NULL && i<idx; ++i)
  204. lp = lp->link;
  205. return &lp->r;
  206. }
  207. cmAlfRC_t cmAudLabelFileWrite( cmAlfH_t h, const cmChar_t* fn )
  208. {
  209. cmAlfRC_t rc = kOkAlfRC;
  210. cmAlf_t* p = _cmAlfHandleToPtr(h);
  211. cmAlfRecd_t* lp = p->list;
  212. cmFileH_t fH = cmFileNullHandle;
  213. if( cmFileOpen(&fH,fn,kWriteFileFl,p->err.rpt) != kOkFileRC )
  214. {
  215. rc = cmErrMsg(&p->err,kFileFailAlfRC,"The audio label output file '%s' could not be created.",cmStringNullGuard(fn));
  216. goto errLabel;
  217. }
  218. for(; lp!=NULL; lp=lp->link)
  219. {
  220. if( cmFilePrintf(fH,"%f %f %s",lp->r.begSecs,lp->r.endSecs,lp->r.label == NULL ? "" : lp->r.label) != kOkFileRC )
  221. {
  222. rc = cmErrMsg(&p->err,kFileFailAlfRC,"The audio label output file write failed.");
  223. goto errLabel;
  224. }
  225. }
  226. errLabel:
  227. if( cmFileClose(&fH) != kOkFileRC )
  228. {
  229. rc = cmErrMsg(&p->err,kFileFailAlfRC,"The audio label output file '%s' close failed.",cmStringNullGuard(fn));
  230. }
  231. return rc;
  232. }
  233. void cmAudLabelFileTest( cmCtx_t* ctx )
  234. {
  235. const cmChar_t* fn = "/home/kevin/temp/labels.txt";
  236. const cmChar_t* ofn = "/home/kevin/temp/labels_out.txt";
  237. cmAlfH_t h = cmAlfNullHandle;
  238. if( cmAudLabelFileAllocOpen(ctx,&h,fn) == kOkAlfRC )
  239. {
  240. unsigned n = cmAudLabelFileCount(h);
  241. unsigned i;
  242. for(i=0; i<n; ++i)
  243. {
  244. const cmAlfLabel_t* lp;
  245. if((lp = cmAudLabelFileLabel(h,i)) != NULL )
  246. cmRptPrintf(&ctx->rpt,"%f %f %s\n",lp->begSecs,lp->endSecs,lp->label);
  247. }
  248. cmAudLabelFileWrite(h,ofn);
  249. cmAudLabelFileFree(&h);
  250. }
  251. }