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.

cmGrPlotAudio.c 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 "cmGlobal.h"
  4. #include "cmFloatTypes.h"
  5. #include "cmRpt.h"
  6. #include "cmErr.h"
  7. #include "cmCtx.h"
  8. #include "cmMem.h"
  9. #include "cmMallocDebug.h"
  10. #include "cmGr.h"
  11. #include "cmGrDevCtx.h"
  12. #include "cmGrPlot.h"
  13. #include "cmAudioFile.h"
  14. #include "cmAudioFileMgr.h"
  15. #include "cmGrPlotAudio.h"
  16. typedef struct
  17. {
  18. cmGrPlObjH_t oH;
  19. cmAfmFileH_t afH;
  20. unsigned chIdx;
  21. cmGrRenderObjCb_t renderCbFunc;
  22. void* renderCbArg;
  23. cmGrDestroyObjCb_t destroyCbFunc;
  24. void* destroyCbArg;
  25. cmGrIsInsideObjCb_t isInsideCbFunc;
  26. void* isInsideCbArg;
  27. void* mem; //
  28. cmGrPExt_t pext; // extents of the visible portion of this audio object
  29. unsigned pixN; // count of pixel columns used by this audio object
  30. cmSample_t* fMinV; // fMinV[pixN] = min sample value for each visible column
  31. cmSample_t* fMaxV; // fMaxV[pixN] = max sample value for each visible column
  32. int* iMinV; // iMinV[pixN] = top pixel for each column line
  33. int* iMaxV; // iMaxV[pixN] = bottom pixel for each column line
  34. } cmGrPlObjAf_t;
  35. cmGrPlRC_t _cmGrPlObjAfCalcImage( cmGrPlObjAf_t* op, cmGrH_t grH )
  36. {
  37. cmGrPlRC_t rc = kOkGrPlRC;
  38. cmGrObjH_t grObjH = cmGrPlotObjHandle(op->oH);
  39. cmGrVExt_t vwExt,objExt,drExt;
  40. // get the intersection of the view and this audio object
  41. cmGrViewExtents( grH, &vwExt );
  42. cmGrPlotObjVExt( op->oH, &objExt );
  43. cmGrVExtIntersect(&drExt,&vwExt,&objExt);
  44. // if the audio object is visible
  45. if( cmGrVExtIsNullOrEmpty(&drExt) )
  46. {
  47. cmGrPExtSetNull(&op->pext);
  48. op->pixN = 0;
  49. }
  50. else
  51. {
  52. // get the extents of the visible portion of the audio object
  53. cmGrVExt_VtoP( grH, cmGrPlotObjHandle(op->oH), &drExt, &op->pext);
  54. // store the count of horizontal pixels
  55. op->pixN = op->pext.sz.w;
  56. // allocate a cache to hold the image data
  57. unsigned byteCnt = op->pixN * 2 * sizeof(int) + op->pixN * 2 * sizeof(cmSample_t);
  58. op->mem = cmMemResize(char,op->mem,byteCnt);
  59. op->fMinV = (cmSample_t*)op->mem;
  60. op->fMaxV = op->fMinV + op->pixN;
  61. op->iMinV = (int*)(op->fMaxV + op->pixN);
  62. op->iMaxV = op->iMinV + op->pixN;
  63. assert( op->iMaxV + op->pixN == op->mem + byteCnt );
  64. // locate the offset into the file of the first sample to be displayed
  65. unsigned si = 0;
  66. if( drExt.loc.x > objExt.loc.x )
  67. si = drExt.loc.x - objExt.loc.x;
  68. // get the floating point audio summary signal
  69. if( cmAfmFileGetSummary( op->afH, op->chIdx, si, drExt.sz.w, op->fMinV, op->fMaxV, op->pixN ) != kOkAfmRC )
  70. {
  71. const cmChar_t* afn = cmAudioFileName( cmAfmFileHandle(op->afH));
  72. rc = cmErrMsg( cmGrPlotErr( cmGrPlotObjMgrHandle(op->oH) ), kRsrcFailGrPlRC, "Audio file summary read failure on '%s'.",afn);
  73. goto errLabel;
  74. }
  75. unsigned i;
  76. // convert the summary to pixels values
  77. for(i=0; i<op->pixN; ++i)
  78. {
  79. // Note the reversal of min and max during the conversion.
  80. op->iMaxV[i] = cmGrY_VtoP( grH, grObjH, op->fMinV[i] );
  81. op->iMinV[i] = cmGrY_VtoP( grH, grObjH, op->fMaxV[i] );
  82. }
  83. }
  84. errLabel:
  85. return rc;
  86. }
  87. bool _cmGrPlObjAfRender( cmGrObjFuncArgs_t* args, cmGrDcH_t dcH )
  88. {
  89. cmGrPlObjAf_t* op = (cmGrPlObjAf_t*)args->cbArg;
  90. if( _cmGrPlObjAfCalcImage(op, args->grH ) == kOkGrPlRC )
  91. {
  92. int i;
  93. cmGrPExt_t pext;
  94. cmGrPhysExtents( args->grH, &pext);
  95. cmGrDcSetColor(dcH, cmGrPlotObjCurLineColor(op->oH));
  96. // draw a horz line at y=0
  97. int y0 = cmGrY_VtoP( args->grH, cmGrPlotObjHandle(op->oH), 0.0 );
  98. cmGrDcDrawLine(dcH, cmGrPExtL(&op->pext), y0, cmGrPExtR(&op->pext) , y0 );
  99. // draw a vertical line for each
  100. for(i=0; i<op->pixN; ++i)
  101. cmGrDcDrawLine(dcH, op->pext.loc.x+i, op->iMinV[i], op->pext.loc.x+i, op->iMaxV[i] );
  102. // draw a rectangle around the entire audio clip
  103. cmGrDcDrawRect(dcH, op->pext.loc.x, cmGrPExtT(&pext), op->pext.sz.w, cmGrPExtB(&pext) );
  104. // draw the file label
  105. cmGrDcDrawTextJustify( dcH, cmGrPlotObjFontFamily(op->oH), cmGrPlotObjFontSize(op->oH), cmGrPlotObjFontStyle(op->oH), cmGrPlotObjLabel(op->oH), &op->pext, kHorzCtrJsGrFl | kTopJsGrFl );
  106. }
  107. return true;
  108. }
  109. bool _cmGrPlObjAfIsInside( cmGrObjFuncArgs_t* args, unsigned evtFlags, int px, int py, cmGrV_t vx, cmGrV_t vy )
  110. {
  111. cmGrPlObjAf_t* op = (cmGrPlObjAf_t*)args->cbArg;
  112. if( cmGrPExtIsXyInside( &op->pext, px, py ) )
  113. {
  114. px -= op->pext.loc.x;
  115. if( 0 <= px && px < op->pixN )
  116. return op->iMinV[px] <= py && py <= op->iMaxV[px];
  117. }
  118. return false;
  119. }
  120. void _cmGrPlObjAfDestroy( cmGrObjFuncArgs_t* args )
  121. {
  122. cmGrPlObjAf_t* op = (cmGrPlObjAf_t*)args->cbArg;
  123. args->cbArg = op->destroyCbArg;
  124. op->destroyCbFunc(args);
  125. cmMemFree(op->mem);
  126. cmMemFree(op);
  127. }
  128. cmGrPlRC_t cmGrPlotAudioFileObjCreate(
  129. cmGrPlObjH_t oH,
  130. cmAfmFileH_t afH,
  131. unsigned audioChIdx )
  132. {
  133. cmGrPlObjAf_t* op = cmMemAllocZ(cmGrPlObjAf_t,1);
  134. op->oH = oH;
  135. op->afH = afH;
  136. op->chIdx = audioChIdx;
  137. cmGrObjH_t grObjH = cmGrPlotObjHandle(op->oH);
  138. op->renderCbFunc = cmGrObjRenderCbFunc(grObjH);
  139. op->renderCbArg = cmGrObjRenderCbArg(grObjH);
  140. cmGrObjSetRenderCb( grObjH, _cmGrPlObjAfRender, op );
  141. op->destroyCbFunc = cmGrObjDestroyCbFunc(grObjH);
  142. op->destroyCbArg = cmGrObjDestroyCbArg(grObjH);
  143. cmGrObjSetDestroyCb( grObjH, _cmGrPlObjAfDestroy, op );
  144. op->isInsideCbFunc = cmGrObjIsInsideCbFunc(grObjH);
  145. op->isInsideCbArg = cmGrObjIsInsideCbArg(grObjH);
  146. cmGrObjSetIsInsideCb( grObjH, _cmGrPlObjAfIsInside, op );
  147. //cmGrPlotObjSetUserPtr(oH,op);
  148. return kOkGrPlRC;
  149. }