libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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. }