Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: foo_wave_seekbar (Read 797223 times) previous topic - next topic
0 Members and 2 Guests are viewing this topic.

foo_wave_seekbar

Reply #1326
I'd suggest you try the direct3d frontend. If you scroll a few posts back you'll find custom frontends. You can either use a fixed height or the replaygain adjusted waveform.
I find this to display the wave more accurately than the blurry GDI frontend.

foo_wave_seekbar

Reply #1327
Propheticus, I use the direct3d frontend, but how do I get a fixed height?

Thanks,

C.
PC = TAK + LossyWAV  ::  Portable = Opus (130)

foo_wave_seekbar

Reply #1328
This is what I'm using atm.
Code: [Select]
	

texture tex : WAVEFORMDATA;

sampler sTex = sampler_state
{
    Texture = (tex);
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
   
    AddressU = Clamp;
};

struct VS_IN
{
    float2 pos : POSITION;
    float2 tc : TEXCOORD0;
};

struct PS_IN
{
    float4 pos : SV_POSITION;
    float2 tc : TEXCOORD0;
};


float4 backgroundColor : BACKGROUNDCOLOR;
float4 highlightColor  : HIGHLIGHTCOLOR;
float4 selectionColor  : SELECTIONCOLOR;
float4 textColor      : TEXTCOLOR;
float cursorPos        : CURSORPOSITION;
bool cursorVisible    : CURSORVISIBLE;
float seekPos          : SEEKPOSITION;
bool seeking          : SEEKING;
float4 replayGain      : REPLAYGAIN; // album gain, track gain, album peak, track peak
float2 viewportSize    : VIEWPORTSIZE;
bool horizontal        : ORIENTATION;
bool flipped          : FLIPPED;
bool shade_played      : SHADEPLAYED;

PS_IN VS( VS_IN input )
{
    PS_IN output = (PS_IN)0;

    float2 half_pixel = float2(1,-1) / viewportSize;
    output.pos = float4(input.pos - half_pixel, 0, 1);

    if (horizontal)
    {
        output.tc = float2((input.tc.x + 1.0) / 2.0, input.tc.y);
    }
    else
    {
        output.tc = float2((-input.tc.y + 1.0) / 2.0, input.tc.x);
    }

    if (flipped)
        output.tc.x = 1.0 - output.tc.x;

    return output;
}

float4 bar( float pos, float2 tc, float4 fg, float4 bg, float width, bool show )
{
    float dist = abs(pos - tc.x);
    float4 c = (show && dist < width)
        ? lerp(fg, bg, smoothstep(0, width, dist))
        : bg;
    return c;
}


float4 evaluate(float4 bg, float4 fg, float factor)
{
        return saturate(lerp(bg, fg, factor));
}

float4 played( float pos, float2 tc, float4 bg, float factor)
{
        float4 c = bg;
        if (pos > tc.x)
        {
                c = evaluate(backgroundColor, highlightColor, factor);
        }
        return c;
}

float RMSfactor( float2 tc, float border )
{
        float4 minmaxrms = tex1D(sTex, tc.x);

// uncomment code below to use replaygain
/*
if(replayGain.r != -1000) {
minmaxrms.rgb *= pow(10,(replayGain.r) / 20) * 1.2; //use album gain
}
else if(replayGain.g != -1000){
minmaxrms.rgb *= pow(10,(replayGain.g) / 20) * 1.2; //use track gain
}
else {
minmaxrms.rgb *= 0.8 + minmaxrms.a;
}*/

//without replaygain (comment out when using the code above)
        minmaxrms.rgb *= 0.8 + minmaxrms.a;

        float belowWave = tc.y + border - minmaxrms.r;
        float aboveWave = tc.y - border - minmaxrms.g;
        float factorWave = min(abs(belowWave), abs(aboveWave));
        bool insideWave = (belowWave > 0 && aboveWave < 0);
     
        float diffRms = abs(tc.y) - border - minmaxrms.b;
        float factorRms = abs(diffRms);
        bool insideRms = diffRms < 0;
     
        float factor = insideRms ? ( 1 + 0.17 * saturate(factorRms / border / 2)): 1.0;
        factor = insideWave ? (factor * saturate(factorWave / border / 1)) : 0.0; //1 = max sharp
     
        return factor;
}

float4 PS( PS_IN input ) : SV_Target
{
        float dx, dy;
        if (horizontal)
        {
                dx = 1/viewportSize.x;
                dy = 1/viewportSize.y;
        }
        else
        {
                dx = 1/viewportSize.y;
                dy = 1/viewportSize.x;
        }
        float seekWidth = 1 * dx;
        float positionWidth = 1 * dx;

        float factor = RMSfactor(input.tc, 2.5 * dy);

        float4 c0 = evaluate(backgroundColor, textColor, factor);
        if (shade_played)
                c0 = played(cursorPos, input.tc, c0, factor);
        c0 = bar(cursorPos, input.tc, selectionColor, c0, positionWidth, cursorVisible);
        c0 = bar(seekPos,  input.tc, selectionColor, c0, seekWidth,    seeking      );
        return c0;
}

technique10 Render10
{
    pass P0
    {
        SetGeometryShader( 0 );
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

technique Render9
{
    pass
    {
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }
}

foo_wave_seekbar

Reply #1329
Thank you Propheticus. I shall play around with that and see what happens. Looks pretty good though!

C.
PC = TAK + LossyWAV  ::  Portable = Opus (130)

foo_wave_seekbar

Reply #1330
carpman

When you say "how do I get a fixed height", do you mean you want all waveforms to have maximum size in the panel, irrespective of the existence of replay gain values?
If so, you may also be interested in my waveform seekbar script for Direct3D . . .

View this screenshot:


Here is my script:
Code: [Select]
texture tex : WAVEFORMDATA;
 
sampler sTex = sampler_state
{
  Texture = (tex);
  MipFilter = LINEAR;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
 
  AddressU = Clamp;
};
 
struct VS_IN
{
  float2 pos : POSITION;
  float2 tc : TEXCOORD0;
};
 
struct PS_IN
{
  float4 pos : SV_POSITION;
  float2 tc : TEXCOORD0;
};
 

float4 chan_mag        : CHANNELMAGNITUDE;  // Requires "foo_wave_seekbar" version 0.2.34 or better
float4 track_mag      : TRACKMAGNITUDE;    // Requires "foo_wave_seekbar" version 0.2.34 or better
float4 backgroundColor : BACKGROUNDCOLOR;
float4 highlightColor  : HIGHLIGHTCOLOR;
float4 selectionColor  : SELECTIONCOLOR;
float4 textColor      : TEXTCOLOR;
float cursorPos        : CURSORPOSITION;
bool cursorVisible    : CURSORVISIBLE;
float seekPos          : SEEKPOSITION;
bool seeking          : SEEKING;
float4 replayGain      : REPLAYGAIN; // album gain, track gain, album peak, track peak
float2 viewportSize    : VIEWPORTSIZE;
bool horizontal        : ORIENTATION;
bool flipped          : FLIPPED;
bool shade_played      : SHADEPLAYED;
 
PS_IN VS( VS_IN input )
{
  PS_IN output = (PS_IN)0;
 
  float2 half_pixel = float2(1,-1) / viewportSize;
  output.pos = float4(input.pos - half_pixel, 0, 1);

  //- - - - - NORMALIZE/RESCALE ALL WAVEFORMS TO FILL PANEL EDGE-TO-EDGE - - - - - - - -
  //Requires "foo_wave_seekbar" version 0.2.34 or better - see changelog
      //This variation will map the range [-1,1] to [min_peak,max_peak].
        input.tc.y = (input.tc.y + 1)/2 * (chan_mag.g - chan_mag.r) + chan_mag.r;
      //This variation will map the range [-1,1] to [-largest_peak,largest_peak]
        //input.tc.y = input.tc.y * max(abs(chan_mag.r), abs(chan_mag.g));

  if (horizontal)
  {
      output.tc = float2((input.tc.x + 1.0) / 2.0, input.tc.y);
  }
  else
  {
      output.tc = float2((-input.tc.y + 1.0) / 2.0, input.tc.x);
  }
 
  if (flipped)
      output.tc.x = 1.0 - output.tc.x;
 
  return output;
}
 
float4 bar( float pos, float2 tc, float4 fg, float4 bg, float width, bool show )
{
  float dist = abs(pos - tc.x);
  float4 c = (show && dist < width)
      ? lerp(fg, bg, smoothstep(0, width, dist))
      : bg;
  return c;
}
 
 
float4 evaluate(float4 bg, float4 fg, float factor)
{
      return saturate(lerp(bg, fg, factor));
}
 
float4 played( float pos, float2 tc, float4 bg, float factor)
{
      float4 c = bg;
      if (pos > tc.x)
      {
              c = evaluate(backgroundColor, highlightColor, factor);
      }
      return c;
}
 
float RMSfactor( float2 tc, float border )
{
      float4 minmaxrms = tex1D(sTex, tc.x);
 
      minmaxrms.rgb -= .1 * minmaxrms.a;

      //- - - - - CHANGES THE OVERALL WAVE SIZE IN THE PANEL - - - - - - - -
      //minmaxrms.rgb *= 0.8 + minmaxrms.a;  <<<<<backup original
        minmaxrms.rgb *= 0.95 + minmaxrms.a;

      float belowWave = tc.y + border - minmaxrms.r;
      float aboveWave = tc.y - border - minmaxrms.g;
      float factorWave = min(abs(belowWave), abs(aboveWave));
      bool insideWave = (belowWave > 0 && aboveWave < 0);
   
      float diffRms = abs(tc.y) - border - minmaxrms.b;
      float factorRms = abs(diffRms);

      //- - - - - ENABLE/DISABLE THE INSIDE WAVE - - - - - - - -
      //  [TO DISABLE:  bool insideRms = 0;]  [TO ENABLE:  bool insideRms = diffRms < 0;  <<<<<backup original]     
        //bool insideRms = diffRms < 0;
        //bool insideRms = (belowWave > 0 && aboveWave < 0);
          bool insideRms = (diffRms > 0 && diffRms < 0);
   
      //- - - - - CHANGES LOOK OF INSIDE WAVE - - - - - - - -
      //float factor = insideRms ? ( 1 + 0.2 * saturate(factorRms / border / 2)): 1.0;  <<<<<backup original
        float factor = insideRms ? ( 6 * saturate(factorRms / border / 20)): 10.0;
 
      //- - - - - CHANGES LOOK OF OUTSIDE WAVE & PANEL BACKGROUND - - - - - - - -
      //factor = insideWave ? (factor * saturate(factorWave / border / 1)) : 0.0;  <<<<<backup original
        factor = insideWave ? (factorRms * 6.0 + 0.8 * saturate(factorWave / border / 0.5)) : 0.0;
 
      //return factor;    <<<<<<backup original
        return insideWave - saturate(factorWave);
}
 
float4 PS( PS_IN input ) : SV_Target
{
      float dx, dy;
      if (horizontal)
      {
              dx = 1/viewportSize.x;
              dy = 1/viewportSize.y;
      }
      else
      {
              dx = 1/viewportSize.y;
              dy = 1/viewportSize.x;
      }
      float seekWidth = 1 * dx;
      float positionWidth = 1 * dx;
 
      float factor = RMSfactor(input.tc, 2.5 * dy);
 
      float4 c0 = evaluate(backgroundColor, textColor, factor);
      if (shade_played)
              c0 = played(cursorPos, input.tc, c0, factor);
      c0 = bar(cursorPos, input.tc, selectionColor, c0, positionWidth, cursorVisible);
      c0 = bar(seekPos,  input.tc, selectionColor, c0, seekWidth,    seeking      );
      return c0;
}
 
technique10 Render10
{
  pass P0
  {
      SetGeometryShader( 0 );
      SetVertexShader( CompileShader( vs_4_0, VS() ) );
      SetPixelShader( CompileShader( ps_4_0, PS() ) );
  }
}
 
technique Render9
{
  pass
  {
      VertexShader = compile vs_2_0 VS();
      PixelShader = compile ps_2_0 PS();
  }
}

BIG THANKS to Zao for updating his component to allow this "faux normalized" effect +++++++++++++++++++++++++++++++

foo_wave_seekbar

Reply #1331
@derty2, yes that's what I meant "faux normalized" like you say.
Thanks, I'll give it a go.

C.
PC = TAK + LossyWAV  ::  Portable = Opus (130)

foo_wave_seekbar

Reply #1332
That faux normalized works pretty well, thanks for mentioning that! I think I'll be using that in my script too.

foo_wave_seekbar

Reply #1333
Is there any way to get Foobar to show which files need to have their seekbar extraced? I.e. show only files where the seekbar has not yet been extracted?

I want to extract all the seekbars for my music but don't want to re-do the ones I have already done as it would take ages (3TB+, Atom D525 processor). 

Thanks!

foo_wave_seekbar

Reply #1334
^i don't think so.

IF you had playback statistics installed, you could make an assumption that anything with a %last_played% date after the db file was created, you'd have a waveform for it.

maybe there is some way to get the file paths out of the db but it probably isn't worth the effort.

foo_wave_seekbar

Reply #1335
Is there any way to get Foobar to show which files need to have their seekbar extraced? I.e. show only files where the seekbar has not yet been extracted?

I want to extract all the seekbars for my music but don't want to re-do the ones I have already done as it would take ages (3TB+, Atom D525 processor). 

Thanks!

I used to provide metadata hooks like %has_seekbar_signature% or such-like in the past, but I think I removed them as they weren't quite the thing that infrastructure was meant for.

If you want to query the database, open wavecache.db with sqlite3.exe, and run the following:
Code: [Select]
.output file-listing.txt
select location,subsong from file;


Combine that with outputting your whole library with foo_texttools or something, and you could probably ad-hoc a playlist file together with the missing entries.
Stay sane, exile.

foo_wave_seekbar

Reply #1336
With the current version (0.2.34), I'm getting different waveforms for a FLAC than for the corresponding WAV. It doesn't matter what display mode I use (D2D, D3D, GDI; downmix doesn't matter).

The FLAC converted back to WAV looks the same as the original WAV from which the FLAC was made. The FLAC, though, looks slightly different.
(I'd post screenshots, but I can't figure out where they're being saved to... no info is in the console.)

Is something wrong?

foo_wave_seekbar

Reply #1337
I have question for Propheticus.
Propheticus, I want to use your code from Post #1329. If I'm not wrong your code provides 2 things, that I don't want to use - first is "fixed height" - which makes all waveforms of the same height, no matter what real amplitudes are in the file. Second is replaygain - I want "real" amplitudes, not replaygained. My question to you is : how should I modify your code to simply use D3D9, use your type of colouring, but without that 2 options?

foo_wave_seekbar

Reply #1338
With the current version (0.2.34), I'm getting different waveforms for a FLAC than for the corresponding WAV. It doesn't matter what display mode I use (D2D, D3D, GDI; downmix doesn't matter).

The FLAC converted back to WAV looks the same as the original WAV from which the FLAC was made. The FLAC, though, looks slightly different.
(I'd post screenshots, but I can't figure out where they're being saved to... no info is in the console.)

Is something wrong?

Maybe. Is this for any FLAC you've encoded or just some particular one? What encoder do you use?

Don't use the built-in screenshot functionality by the way, that has never been a supported feature. I don't remember how/if it's supposed to work and will be removing it in later versions.
Just use the Windows functionality and/or ShareX to capture screenshots.
Stay sane, exile.

foo_wave_seekbar

Reply #1339
@EpicForever

The code I posted above has the replaygain part commented out, so it already uses the actual amplitude data. You can change the 0.8 value in the 'without replaygain' code to either prevent it running out of bounds/left and right overlapping or widen it. This is an overall width setting, not normalization. Only when you uncomment (remove /* and */) the part where I indicated it in the file, replaygain data will be used. I left both pieces of code in to leave the choice to the user whether or not to use replaygain compensation.

Long story short: It should already work like requested without editing anything.

foo_wave_seekbar

Reply #1340
Many thanks Propheticus !!
Many thanks derty2 - your version is also nice

I have additional question. What if I like colouring from the default D3D9 script, but I want it to be as sharp as waveform displayed by Propheticus and derty2 scripts? Default script is as blurry on the edges as GDI. Which parts of code should be replaced in default script to achieve only sharpness, but leave default colouring intact?

foo_wave_seekbar

Reply #1341
With the current version (0.2.34), I'm getting different waveforms for a FLAC than for the corresponding WAV. [...] Is something wrong?

Maybe. Is this for any FLAC you've encoded or just some particular one? What encoder do you use?

It seems to happen with all FLACs, and the encoder doesn't matter. (Flake, libFLAC). It doesn't matter if you start with a WAV and convert it to FLAC, or vice-versa.



That's for a 5-minute song. Now look at a 41-second clip:



Are you able to reproduce it? Just use a WAV and FLAC with same audio, and see if the waveforms are the same.

foo_wave_seekbar

Reply #1342
Yes, I've reproduced it, and am trying to drill down into why two decodes considered equivalent by foo_bitcompare result in different signatures.

Unless I'm severely misusing the decoder interface and I'm missing some kind of flag, there's probably a bug in the bucket division code, or that the file formats generate chunks of varying sizes.
Stay sane, exile.

foo_wave_seekbar

Reply #1343
Found the bug, a fix will appear whenever I manage to make a public build.
It turns out that if a chunk from the decoder straddled several analysis buckets, the trailing buckets didn't offset into the chunk, instead repeating the beginning of it.
Stay sane, exile.

foo_wave_seekbar

Reply #1344
Thanks for checking into it! Glad it wasn't just me. We'll probably have to rebuild our databases, eh?

foo_wave_seekbar

Reply #1345
It must be hard to code (I presume, I'm no dev.), but it'd be nice if there was an option that could show you in red where there's clipping, kinda like what Audacity does.

foo_wave_seekbar

Reply #1346
In the shader code, test if the min sample is less than negative one, or if the max sample is above one. If so, just use a different color for the functions, or just early-out with solid red.
Stay sane, exile.

foo_wave_seekbar

Reply #1347
Thanks for checking into it! Glad it wasn't just me. We'll probably have to rebuild our databases, eh?

You need to remove and recreate your waveforms if you want the subtle correctness improvement this provides, yes. I'll put a note in the changelog when it's released.
Sadly this affects pretty much any waveform generated this year.

As a side note, the upcoming release will be the first using Visual Studio 11's XP-compatible compiler, and it will also depend on the dynamic runtime, due to not being able to build my dependencies against the static runtime anymore.
(that is, the runtime for Visual Studio 2012 Update 1)
Stay sane, exile.


foo_wave_seekbar

Reply #1349
Things added in edits do not show up in my email inbox, so they're extremely easy to miss.

The default effect does a linear interpolation (with the lerp function) from the background colour to the inside colour, like:
Code: [Select]
float4 wave = outside
  ? bgColor
  : lerp(bgColor, textColor, 7.0*factor);

The part after the ? is the colour to use for pixels outside of the waveform, while the part after the : is for pixels inside the waveform. No matter how you mess with these functions, you will still have the clear distinction between inside and outside fragments. It's just that the default look makes it approach the background colour from the inside. The factor parameter is related to the vertical distance from the edge, kind of.

You can bias this by twidding the interpolation parameter somewhat, like:
Code: [Select]
lerp(bgColor, textColor, 7.0*factor + 0.7)

This makes it not quite reach the background colour, but instead targets a colour inbetween as the boundary.

This is where artfulness and toying around comes in
Stay sane, exile.