Support

If you have a problem or need to report a bug please email : support@dsprobotics.com

There are 3 sections to this support area:

DOWNLOADS: access to product manuals, support files and drivers

HELP & INFORMATION: tutorials and example files for learning or finding pre-made modules for your projects

USER FORUMS: meet with other users and exchange ideas, you can also get help and assistance here

NEW REGISTRATIONS - please contact us if you wish to register on the forum

Users are reminded of the forum rules they sign up to which prohibits any activity that violates any laws including posting material covered by copyright

Render a View to a Bitmap - Some questions

For general discussion related FlowStone

Re: Render a View to a Bitmap - Some questions

Postby tulamide » Wed Jan 27, 2016 12:55 am

Nubeat7 wrote:here is a slightly more optimized "direct draw version"

the graphics paths are also done in the coordinates methode now, so only called when updating the wavefile,
and only pure drawing in the draw methode.
The redraw rate for the playposition line is reduced to 50 ticks instead of 100, works pretty smooth , it should be close to the screenupdate rate from normally 60 hz..

also it just needs to redraw one layer instead of 2 when you draw on top of a bitmap..

some testings with your 10 samplers would be interesting if it makes any difference between bitmap or direct drawing..

Awesome job! Really, it's brilliant. I wouldn't know what to improve. The playposition can go down to 30 ticks if you want to, because human eyes see a motion starting at around 18 fps, so even at 30 ticks it would be smooth (In cinemas you see 24 fps). But I doubt that it will matter much.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Render a View to a Bitmap - Some questions

Postby Nowhk » Wed Jan 27, 2016 6:46 pm

You are awesome guys! Really, I've learnt a lot from this topc! Thanks, many thanks!!!!
Yeah, your code looks brilliant Nubeat7.

It will suffer only one problems: the number of channels. When I make the path that will be draw, I need to decide if the wave is mono or stereo (because the draw will be different). WaveFile prim will first trigger the mem array prim, than the number of channels. So you have to create the drawing path when you get the number of channels, not the wave. Thus, the "trigger" to draw the new path must go to the Number of Channels connector. But when you re-load the schematic, it triggers only Mem connector (since M2F trigger once loaded), not the number of channels.

i.e. I cannot set two different triggers for the same task (one when I just reload schematic; one when I change to a new sample). Or at least: I don't know how to manage this situation.

This is my actual code (I prefer to stay inside Ruby; as you can see, Mono or Stereo will draw two different kind of Waveform, so I need to know this information before draw it. And this information come to me after Mem, due to how WaveFile output triggers once loaded a wavefile):

Code: Select all
def setParameters
   @width,@height = getViewSize 0
   @rescaling = 0.9   
   @factor_s = @n_channels == 2 ? 0.5 : 1
   @sample_block_size = (@samples.length*@factor_s)/(@width*8)
   @s = @width/(@samples.length*@factor_s)
   @h = @height*0.5*@factor_s   
   
   @penPeaks = Pen.new Color.new(255,128,255,255),0.1
   @penPeaks.setLineJoin "round"
   @penSeparator = Pen.new Color.new(50,255,255,255),0.1   
   @brushBackground = Brush.new @color_background   
   @brushPeaks = Brush.new Color.new(255,128,255,255)         
end

def getCoordinates
   @path = GraphicsPath.new   

   # Stereo
   if(@n_channels == 2)
      # Left
      peaksMax = []
      peaksMin = []      
      step = 0
      max = -1
      min = 1

      0.step(@samples.length-1, 2) do |i|
         step += 1
         max = @samples[i] > max ? @samples[i] : max
         min = @samples[i] < min ? @samples[i] : min
         if step >= @sample_block_size
            peaksMax << [i*@factor_s*@s,(@h-max*@h*@rescaling)]
            peaksMin << [i*@factor_s*@s,(@h-min*@h*@rescaling)]
            step = 0
            max = -1
            min = 1
         end
      end

      @path.addLines peaksMax
      @path.addLines peaksMin.reverse!
      @path.closeFigure      
      
      # Right
      peaksMax = []
      peaksMin = []      
      step = 0
      max = -1
      min = 1

      1.step(@samples.length-1, 2) do |i|
         step += 1
         max = @samples[i] > max ? @samples[i] : max
         min = @samples[i] < min ? @samples[i] : min
         if step >= @sample_block_size
            peaksMax << [(i-1)*@factor_s*@s,(@h-max*@h*@rescaling)+@h*2]
            peaksMin << [(i-1)*@factor_s*@s,(@h-min*@h*@rescaling)+@h*2]
            step = 0
            max = -1
            min = 1
         end
      end

      @path.addLines peaksMax
      @path.addLines peaksMin.reverse!
      @path.closeFigure                        
   # Mono         
   elsif(@n_channels == 1)   
      peaksMax = []
      peaksMin = []      
      step = 0
      max = -1
      min = 1         
      0.step(@samples.length-1) do |i|
         step += 1
         max = @samples[i] > max ? @samples[i] : max
         min = @samples[i] < min ? @samples[i] : min
         if step >= @sample_block_size
            peaksMax << [i*@s,(@h-max*@h*@rescaling)]
            peaksMin << [i*@s,(@h-min*@h*@rescaling)]
            step = 0
            max = -1
            min = 1
         end
      end      

      @path.addLines peaksMax
      @path.addLines peaksMin.reverse!
      @path.closeFigure         
   end
end

def draw i,v
   # Background
   v.drawRectangle @brushBackground,[0,0,@width,@height]      

   # Waveform
   v.drawPath @path,@penPeaks         
   v.drawPath @path,@brushPeaks
   
   # Separator
   if(@n_channels == 2 || @n_channels == 0)
      v.drawLine @penSeparator,[0,@height/2],[@width,@height/2]      
   end   
end

def event i,v
   if(i=="init")
      setParameters
   elsif(i=="n_channels")
      setParameters
      getCoordinates
      redraw 0      
   end
end

Notice the trigger to draw is on "n_channels", which is not called once I load the schematic.

This will also introduce another problem: when you change the sample as VST.
Let say you load SampleA and save the schematic, than export as VST.

When you load, it first will load the wave inside the schematic, and that's ok. If now I change the sample (SampleB) and I store the path to the preset (for reload it next loading), when I reload it will load first the wave inside the schematic, than the sample stored in preset:

Immagine.png
Immagine.png (12.09 KiB) Viewed 15929 times

If you look at Trigger counter when you load the VST first time (no data in preset), you will see count 1 (the wave stored on schematic when you export as VST).
If you now change the sample (which will store the path to Preset String), save the preset and reload, count is 2 (it first load schematic one, than from VST).

Two times! And this makes trouble, since there are two scenario, where in one you don't have informations about channels, and one with trigger twice and send wave + n of channels.

Is it clear what I mean?
Nowhk
 
Posts: 275
Joined: Mon Oct 27, 2014 6:45 pm

Re: Render a View to a Bitmap - Some questions

Postby Nubeat7 » Wed Jan 27, 2016 10:28 pm

Nowhk wrote:It will suffer only one problems: the number of channels.


i know, as i said above, its just for stereo files, but it shouldn't be too hard too set a mono / steroe flag, but it will need some investigation, there is also no error handling inside which should also be done..
i didn't tested it a lot, so maybe there are some more things to fix..

about the usage as vst including preset management is another story which will need some more investigation too..
and lot of fun with midi cc bindings :mrgreen: and ASM optimizations

i would go step by step, first solve the stereo mono issue then the loading and preset stuff as vst
all the preset management is often pretty difficult and tricky to solve..

sadly i have really spare time to do some programming, but i think you have a good startpoint now to solve this things, just investigate some time into trigger handling in FS, thats one of the most important tasks here, just know each single trigger in your schematic, know when and where it happens and you are done ;)

your project sounds really interesting, and really big :D maybe it would be a cool forum project, i'm sure some people in here would be interested to work and help on different parts, and it would have a lot of learning potential for you and others..
User avatar
Nubeat7
 
Posts: 1347
Joined: Sat Apr 14, 2012 9:59 am
Location: Vienna

Re: Render a View to a Bitmap - Some questions

Postby Nubeat7 » Wed Jan 27, 2016 11:19 pm

but seems to work fine with just setting a flag for stereo...
Attachments
waveplayer_nubeat7e.fsm
(173.28 KiB) Downloaded 842 times
User avatar
Nubeat7
 
Posts: 1347
Joined: Sat Apr 14, 2012 9:59 am
Location: Vienna

Re: Render a View to a Bitmap - Some questions

Postby Nowhk » Thu Jan 28, 2016 12:35 pm

Nubeat7 wrote:but seems to work fine with just setting a flag for stereo...

Uhm... I don't understand why you get "update" and "stereo" trigger at the same time:

Code: Select all
when :update
   getCoordinates
   redraw 0
   watch "t1", time
when :stereo
   watch "t2", time

it prints the same time! In my example instead, update is triggered (sometimes) before stereo, and this is a huge problem, since the "update trigger" will create data to draw where the number of channels is missing.
This is the way I process it:

Immagine.png
Immagine.png (32.42 KiB) Viewed 15907 times

why this happens "sometimes"? Try clicking on the Trigger many times (10/20 times): at some points you will see the value of tdiff with the value, and if you looks at the times, they are different (looks at the pic). I don't know where the issue born...
Maybe it process "[F]" (update) at different ticks of I (stereo) in Ruby's event stack? So that difference in time? How can I fix this? Double flag?

test.fsm
(1018.49 KiB) Downloaded 828 times

(note you need to put some samples path inside the array to switch random to them and looks at the results. Try with samples with huge size for better results)
Nowhk
 
Posts: 275
Joined: Mon Oct 27, 2014 6:45 pm

Re: Render a View to a Bitmap - Some questions

Postby Nubeat7 » Thu Jan 28, 2016 2:55 pm

there are two ways to fix this, program the wavedrawer in a way where it doesn't matter what the stereo flag says, or if you are sure that it is a timing thing you can sample and hold the wave and give it free after the channels are setted

so the first connection of the channels output goes to your ruby wavedrawer and the second triggers the sample and hold to send the wavefile to the wavedrawer...
User avatar
Nubeat7
 
Posts: 1347
Joined: Sat Apr 14, 2012 9:59 am
Location: Vienna

Re: Render a View to a Bitmap - Some questions

Postby Nowhk » Thu Jan 28, 2016 3:13 pm

Nubeat7 wrote:there are two ways to fix this, program the wavedrawer in a way where it doesn't matter what the stereo flag says

:shock: How do you decide if the wave is stereo or mono without this info?

Nubeat7 wrote:so the first connection of the channels output goes to your ruby wavedrawer and the second triggers the sample and hold to send the wavefile to the wavedrawer...

Sure :) But as I said before, this only happens when I load a sample from Wave Loader. Instead, when I just load the schematic, the "stereo" field won't be triggered to Ruby (it just read/refresh value on the connector->@stereo; no trigger happens). That's the problem...

Also, it's strange enough that Mem (which takes couble of ms to read/send [F] to Ruby) happens at the same time of Number of Channels trigger (when they happens together). Or is it the time Ruby will read from connector at fixed tick?
I thought that once Ruby reach a trigger, it just process the event one after one. But it seems it stacks them and process at fixed tick (I guess; it is not written in manual, I don't find this information).
Nowhk
 
Posts: 275
Joined: Mon Oct 27, 2014 6:45 pm

Re: Render a View to a Bitmap - Some questions

Postby tulamide » Thu Jan 28, 2016 3:45 pm

Nowhk wrote:But as I said before, this only happens when I load a sample from Wave Loader. Instead, when I just load the schematic, the "stereo" field won't be triggered to Ruby (it just read/refresh value on the connector->@stereo; no trigger happens). That's the problem...

It is really important to not only read the user guide/component reference, but repeatedly consult it. You would have been aware that there is a prim called "After load", which is triggered once, you guess, after the schematic has loaded.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: Render a View to a Bitmap - Some questions

Postby Nowhk » Thu Jan 28, 2016 5:14 pm

tulamide wrote:
Nowhk wrote:But as I said before, this only happens when I load a sample from Wave Loader. Instead, when I just load the schematic, the "stereo" field won't be triggered to Ruby (it just read/refresh value on the connector->@stereo; no trigger happens). That's the problem...

It is really important to not only read the user guide/component reference, but repeatedly consult it. You would have been aware that there is a prim called "After load", which is triggered once, you guess, after the schematic has loaded.

Yes I've thought about it, but I don't know if that's the right choice.

What's the best approch in this case? Invoke the drawing on "stereo" connector and set an After Load to it?
Because my worry (since I don't get how Ruby schedule the events) is that can also happens that "stereo" will be triggered before "samples".

In few words: is it possible that WaveFile's final destination trigger is "stereo" before "samples"?

Immagine.png
Immagine.png (13.97 KiB) Viewed 15899 times

Or the order on where the connector trigger arrive to Ruby follow the order on where they are placed from the Prism (WaveMem is on top than Number of Channel, that is in the bottom)?
Nowhk
 
Posts: 275
Joined: Mon Oct 27, 2014 6:45 pm

Re: Render a View to a Bitmap - Some questions

Postby tulamide » Thu Jan 28, 2016 5:50 pm

Nowhk wrote:What's the best approch in this case? Invoke the drawing on "stereo" connector and set an After Load to it?
Because my worry (since I don't get how Ruby schedule the events) is that can also happens that "stereo" will be triggered before "samples".

In few words: is it possible that WaveFile's final destination trigger is "stereo" before "samples"?

Or the order on where the connector trigger arrive to Ruby follow the order on where they are placed from the Prism (WaveMem is on top than Number of Channel, that is in the bottom)?

You said you are a programmer, and mentioned C sharp. But all your question tell me that you never before programmed in an object oriented, event driven, multi-tasking, multi-threaded, multi-core environment.

So let me point out: You may never rely on anything! Don't assume an order, in which events will be triggered. Don't try to force or prevent a redrawing. Don't try to do that 30 year old, static top to bottom executed code. That doesn't work in modern programming languages.

For example, there's a method that's executed on an event. You have multiple inputs that can cause the event method to execute. Therefore it's your responsibility to create code that deals with each possible scenario of events. If you want to first evaluate "stereo" before "samples", program it that way. Wait until both triggers happened, then execute your branch of code that deals with mono or stereo, depending on the stereo tigger.

Code: Select all
def event i, v
    if i == "samples"
        @triggers = @triggers | 1
    elsif i == "stereo"
        @triggers = @triggers | 2
    end
    if @triggers & 3 == 3
        #now both triggers happened, both data are available
        #...do whatever code
        @triggers = 0
    end
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

PreviousNext

Return to General

Who is online

Users browsing this forum: No registered users and 56 guests