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.9KB

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