Skip to main content

Topic: foo_wave_seekbar (Read 507372 times) previous topic - next topic

0 Members and 2 Guests are viewing this topic.
  • Innomen
  • [*]
foo_wave_seekbar
Reply #1325
I love waveform seekbar.

Pursuant to a suggestion I received in this thread (http://www.hydrogenaudio.org/forums/index.php?s=&showtopic=100528&view=findpost&p=832221) I am suggesting/requesting (sort of) a spectrograph seek bar.

Many of my songs end up with near solid bars for waveform output as if they were white noise, but when viewed as a spectrograph their complexity is revealed.

  • Propheticus
  • [*][*][*]
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.

  • carpman
  • [*][*][*][*][*]
  • Developer
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 = Lame MP3

  • Propheticus
  • [*][*][*]
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();
   }
}

  • carpman
  • [*][*][*][*][*]
  • Developer
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 = Lame MP3

  • derty2
  • [*][*][*][*][*]
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 +++++++++++++++++++++++++++++++

  • carpman
  • [*][*][*][*][*]
  • Developer
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 = Lame MP3

  • Propheticus
  • [*][*][*]
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!
  • Last Edit: 25 April, 2013, 05:46:04 PM by extracampine

  • marc2003
  • [*][*][*][*][*]
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.
  • Last Edit: 26 April, 2013, 10:08:37 AM by marc2003

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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.
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.

  • mjb2006
  • [*][*][*][*][*]
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?
  • Last Edit: 02 May, 2013, 12:04:29 AM by mjb2006

  • EpicForever
  • [*][*][*][*][*]
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?

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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.
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.

  • Propheticus
  • [*][*][*]
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.
  • Last Edit: 02 May, 2013, 07:01:13 AM by Propheticus

  • EpicForever
  • [*][*][*][*][*]
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?
  • Last Edit: 02 May, 2013, 03:46:10 PM by EpicForever

  • mjb2006
  • [*][*][*][*][*]
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.

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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.
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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.
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.

  • mjb2006
  • [*][*][*][*][*]
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?
  • Last Edit: 02 May, 2013, 08:58:27 PM by mjb2006

  • Aldem
  • [*][*][*]
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.

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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.
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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)
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.

  • EpicForever
  • [*][*][*][*][*]
foo_wave_seekbar
Reply #1348
Sorry for bothering while such important questions are discussed, but how about my question from my previous post?
http://www.hydrogenaudio.org/forums/index....st&p=833144  ?

  • Zao
  • [*][*][*][*][*]
  • Members (Donating)
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
  • Last Edit: 03 May, 2013, 05:13:59 AM by Zao
Zao shang yong zao nong zao rang zao ren zao.
To, early in the morning, use a chisel to build a bathtub makes impatient people hot-tempered.