Advertisement
Delfigamer

spectrum.cpp

Feb 14th, 2018
430
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.54 KB | None | 0 0
  1. #include <common.hpp>
  2. #include <vector>
  3. #include <cmath>
  4. #include <cstdio>
  5.  
  6. struct spectrumdraw_interface_t
  7. {
  8.     int32_t const* samples;
  9.     unsigned int samplecount;
  10.     unsigned int samplescale;
  11.     unsigned int channelcount;
  12.     unsigned int samplerate;
  13.     unsigned int bitmapwidth;
  14.     float freqbase;
  15.     unsigned int freqdivision; // number of frequencies per octave
  16.     unsigned int freqcount;
  17.     uint8_t* bitmap;
  18. };
  19.  
  20. namespace
  21. {
  22. namespace spectrumdraw_private
  23. {
  24.     float const pi = 3.14159265359f;
  25.     int const batchsize = 1;
  26.     // 1 // 300
  27.     // 2 // 258
  28.     // 16 // 261
  29.     // 660 // 276
  30.  
  31.     int abs( int x )
  32.     {
  33.         return x * ( x >> 31 );
  34.     }
  35.  
  36.     class filter_t
  37.     {
  38.     private:
  39.         struct state_t
  40.         {
  41.             float a;
  42.             float b;
  43.         };
  44.  
  45.     private:
  46.         float m_res_aa;
  47.         float m_res_ab;
  48.         float m_res_au;
  49.         float m_res_ba;
  50.         float m_res_bb;
  51.         float m_res_bu;
  52.         float m_res_yb;
  53.         float m_res_ybsqr;
  54.         state_t m_state[ 2 ];
  55.         float m_powerbuf;
  56.         size_t m_powersamplecount;
  57.  
  58.     public:
  59.         filter_t() = default;
  60.         ~filter_t() = default;
  61.  
  62.         void init( int sr, float freq );
  63.         void feed( float u );
  64.         float getpowermean();
  65.     };
  66.  
  67.     void filter_t::init( int sr, float freq )
  68.     {
  69.         float xi = 0.03f;
  70.         float sp = 1.0f / sr;
  71.         float T = 1 / ( 2 * pi * freq );
  72.         float scale = exp( - sp * xi / T );
  73.         if( xi < 1 )
  74.         {
  75.             float xisqrt = sqrt( 1 - xi*xi );
  76.             float phase = sp * xisqrt / T;
  77.             float phasecosv = cos( phase );
  78.             float phasesinv = sin( phase ) / xisqrt;
  79.             m_res_aa = scale * ( phasecosv + xi * phasesinv );
  80.             m_res_ba = - scale * phasesinv;
  81.             m_res_ab = scale * phasesinv;
  82.             m_res_bb = scale * ( phasecosv - xi * phasesinv );
  83.             m_res_au = ( 1 - scale * ( phasecosv + xi * phasesinv ) );
  84.             m_res_bu = scale * phasesinv;
  85.             m_res_yb = 2 * xi;
  86.         }
  87.         else if( xi > 1 )
  88.         {
  89.             float xisqrt = sqrt( xi*xi - 1 );
  90.             float phase = sp * xisqrt / T;
  91.             float scale2 = exp( - sp * ( xi + xisqrt ) / T );
  92.             float phasecoshv = cosh( phase );
  93.             float phasesinhv = sinh( phase ) / xisqrt;
  94.             float phaseexpv = exp( 2 * phase );
  95.             m_res_aa = scale * ( phasecoshv + xi * phasesinhv );
  96.             m_res_ba = - scale * phasesinhv;
  97.             m_res_ab = scale * phasesinhv;
  98.             m_res_bb = scale * ( phasecoshv - xi * phasesinhv );
  99.             m_res_au = - 0.5 * scale2 * ( ( phaseexpv - 1 ) * xi +
  100.                 ( phaseexpv + 1 - 2/scale2 ) * xisqrt ) / xisqrt;
  101.             m_res_bu = scale * phasesinhv;
  102.             m_res_yb = 2 * xi;
  103.         }
  104.         else
  105.         {
  106.             m_res_aa = scale * ( T + sp ) / T;
  107.             m_res_ba = - scale * sp / T;
  108.             m_res_ab = scale * sp / T;
  109.             m_res_bb = scale * ( T - sp ) / T;
  110.             m_res_au = scale * ( ( exp( sp / T ) - 1 ) * T - sp ) / T;
  111.             m_res_bu = scale * sp / T;
  112.             m_res_yb = 2;
  113.         }
  114.         m_res_ybsqr = m_res_yb*m_res_yb;
  115.         for( auto& state : m_state )
  116.         {
  117.             state.a = 0;
  118.             state.b = 0;
  119.         }
  120.         m_powerbuf = 0;
  121.         m_powersamplecount = 0;
  122.     }
  123.  
  124.     void filter_t::feed( float u )
  125.     {
  126.         float na = 0;
  127.         float nb = 0;
  128.         for( auto& state : m_state )
  129.         {
  130.             na = m_res_aa * state.a + m_res_ab * state.b + m_res_au * u;
  131.             nb = m_res_ba * state.a + m_res_bb * state.b + m_res_bu * u;
  132.             state.a = na;
  133.             state.b = nb;
  134.             u = m_res_yb * nb;
  135.         }
  136.         m_powerbuf += ( na*na + nb*nb ) * m_res_ybsqr;
  137.         m_powersamplecount += 1;
  138.     }
  139.  
  140.     float filter_t::getpowermean()
  141.     {
  142.         if( m_powersamplecount == 0 )
  143.         {
  144.             return 0;
  145.         }
  146.         float ret = m_powerbuf / m_powersamplecount;
  147.         m_powerbuf = 0;
  148.         m_powersamplecount = 0;
  149.         return ret;
  150.     }
  151.  
  152.     float clampf( float c )
  153.     {
  154.         return ( fabs( c ) - fabs( c - 1.0f ) + 1.0f ) * 0.5f;
  155.     }
  156.  
  157.     // cc 0 1 2 3 4 5 6
  158.     // R 0 0 0 0<<1 1 1
  159.     // G 0 0<<1 1 1>>0<<1
  160.     // B 0<<1 1>>0 0 0<<1
  161.     // black < blue < cyan < green < yellow < red < white
  162.     void setpixel( uint8_t* pixel, float c )
  163.     {
  164.         float cc = clampf( c ) * 6.0f;
  165.         float d = fmod( cc, 1.0f );
  166.         if( cc < 1 )
  167.         {
  168.             pixel[ 0 ] = 0;
  169.             pixel[ 1 ] = 0;
  170.             pixel[ 2 ] = 255 * d;
  171.             pixel[ 3 ] = 255;
  172.         }
  173.         else if( cc < 2 )
  174.         {
  175.             pixel[ 0 ] = 0;
  176.             pixel[ 1 ] = 255 * d;
  177.             pixel[ 2 ] = 255;
  178.             pixel[ 3 ] = 255;
  179.         }
  180.         else if( cc < 3 )
  181.         {
  182.             pixel[ 0 ] = 0;
  183.             pixel[ 1 ] = 255;
  184.             pixel[ 2 ] = 255 * ( 1 - d );
  185.             pixel[ 3 ] = 255;
  186.         }
  187.         else if( cc < 4 )
  188.         {
  189.             pixel[ 0 ] = 255 * d;
  190.             pixel[ 1 ] = 255;
  191.             pixel[ 2 ] = 0;
  192.             pixel[ 3 ] = 255;
  193.         }
  194.         else if( cc < 5 )
  195.         {
  196.             pixel[ 0 ] = 255;
  197.             pixel[ 1 ] = 255 * ( 1 - d );
  198.             pixel[ 2 ] = 0;
  199.             pixel[ 3 ] = 255;
  200.         }
  201.         else if( cc < 6 )
  202.         {
  203.             pixel[ 0 ] = 255;
  204.             pixel[ 1 ] = 255 * d;
  205.             pixel[ 2 ] = pixel[ 1 ];
  206.             pixel[ 3 ] = 255;
  207.         }
  208.         else
  209.         {
  210.             pixel[ 0 ] = 255;
  211.             pixel[ 1 ] = 255;
  212.             pixel[ 2 ] = 255;
  213.             pixel[ 3 ] = 255;
  214.         }
  215.     }
  216. }
  217. }
  218.  
  219. using namespace spectrumdraw_private;
  220.  
  221. extern "C"
  222. __declspec( dllexport )
  223. void spectrumdraw_main( spectrumdraw_interface_t const* interface )
  224. {
  225.     filter_t filters[ batchsize ];
  226.     int samplereduction = interface->samplecount / interface->bitmapwidth;
  227.     size_t bitmapstride = interface->bitmapwidth * 4;
  228.     for(
  229.         unsigned ystart = 0;
  230.         ystart < interface->freqcount;
  231.         ystart += batchsize )
  232.     {
  233.         printf( "%i/%i\n", ystart, interface->freqcount );
  234.         for(
  235.             unsigned y = ystart;
  236.             y < ( ystart + batchsize ) && y < interface->freqcount;
  237.             y += 1 )
  238.         {
  239.             float frequency = interface->freqbase
  240.                 * pow( 2.0f, ( float )y / interface->freqdivision );
  241.             filters[ y - ystart ].init( interface->samplerate, frequency );
  242.         }
  243.         int32_t const* currentsample =
  244.             interface->samples;
  245.         int32_t const* sampleend =
  246.             interface->samples +
  247.             interface->samplecount * interface->channelcount;
  248.         float ampfactor =
  249.             1 / ( ( float )interface->channelcount * interface->samplescale );
  250.         int powersamplecount = 0;
  251.         uint8_t* currentpixel =
  252.             interface->bitmap;
  253.         while( currentsample != sampleend )
  254.         {
  255.             float value;
  256.             if( interface->channelcount == 1 )
  257.             {
  258.                 value = currentsample[ 0 ];
  259.                 currentsample += 1;
  260.             }
  261.             else if( interface->channelcount == 2 )
  262.             {
  263.                 value = currentsample[ 0 ] + currentsample[ 1 ];
  264.                 currentsample += 2;
  265.             }
  266.             else
  267.             {
  268.                 ASSERT( false );
  269.                 value = currentsample[ 0 ];
  270.             }
  271.             value *= ampfactor;
  272.             for(
  273.                 unsigned y = ystart;
  274.                 y < ( ystart + batchsize ) && y < interface->freqcount;
  275.                 y += 1 )
  276.             {
  277.                 filters[ y - ystart ].feed( value );
  278.             }
  279.             powersamplecount += 1;
  280.             if( powersamplecount == samplereduction )
  281.             {
  282.                 for(
  283.                     unsigned y = ystart;
  284.                     y < ( ystart + batchsize ) && y < interface->freqcount;
  285.                     y += 1 )
  286.                 {
  287.                     setpixel(
  288.                         currentpixel + bitmapstride * y,
  289.                         filters[ y - ystart ].getpowermean() );
  290.                 }
  291.                 currentpixel += 4;
  292.                 powersamplecount = 0;
  293.             }
  294.         }
  295.     }
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement