Old 06-25-2019, 06:19 AM   #1
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default Q: JSFX: Index all PNG files of a /data directory ?

Hi,


In JSFX we can either,


  • load image file with direct path using filename
  • have a list of all files in .data subdirectory if it is wav, .txt, .ogg, or .raw with /some_path:default_value:
Q: How do you get a list of all .png (or .jpg) files in a folder ?
(aka, to have a dropdown list of PNG files for eg. Or even without GUI if not possible.)


Thx !
X-Raym is offline   Reply With Quote
Old 06-25-2019, 10:27 AM   #2
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

I'm not aware of an API like that.

For your use-case (the pads), would it work to have 32 known images included with the effect - e.g. 16 defaults with common icons, 16 ones called "custom01.png" which the user was expected to modify for their specific system?

It wouldn't be portable across systems, so the custom images would end up as either the default state or an incorrect image. (Unless the custom images were also saved to the effect state, and only re-loaded when requested, but that would take up a lot of space in the project state.)
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-25-2019 at 10:42 AM.
geraintluff is offline   Reply With Quote
Old 06-25-2019, 10:28 AM   #3
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Alternatively, you could let them draw their own pixel-art.

Code:
desc:Custom drawing demo

@init
/****** Config ******/
custom_icon_square_size = 9; // Icons are 9x9 squares
custom_icon_count = 16;

/***************/

function encodeRGB(r, g, b) (
  r = min(1, max(0, r));
  g = min(1, max(0, g));
  b = min(1, max(0, b));
  r = floor(r*255 + 0.5);
  g = floor(g*255 + 0.5);
  b = floor(b*255 + 0.5);
  r + 256*g + 65536*b;
);
function decodeRGB(packed, r*, g*, b*) (
  r = (packed%256)/255;
  g = (floor(packed/256)%256)/255;
  b = floor(packed/65536)/255;
);

freemem = 0;
custom_icon_step = custom_icon_square_size*custom_icon_square_size;
freemem = (custom_icons = freemem) + custom_icon_step*custom_icon_count;

!had_init ? (
  had_init = 1;
  editor_r = editor_g = editor_b = 0.5;
);

@gfx

function iconToScreenBuffer(icon_index, screen_index) local(old_dest, icon_memory, x, y, pixel) (
  gfx_setimgdim(screen_index, icon_square_size, icon_square_size);
  old_dest = gfx_dest;
  gfx_dest = screen_index;
  icon_memory = custom_icons + custom_icon_step*icon_index;
  
  y = 0;
  loop(icon_square_size,
    x = 0;
    loop(icon_square_size,
      pixel = x + y*icon_square_size;
      decodeRGB(icon_memory[pixel], gfx_r, gfx_g, gfx_b);
      gfx_x = x;
      gfx_y = y;
      gfx_setpixel(gfx_r, gfx_g, gfx_b);
      x += 1;
    );
    y += 1;
  );
  
  gfx_dest = old_dest;
);

function drawIconEditor(icon_index, origin_x, origin_y, size) local(pixel_scale, x, y, pixel, prev_editor_drawing) (
  pixel_scale = size/custom_icon_square_size;
  y = 0;
  loop(custom_icon_square_size,
    x = 0;
    loop(custom_icon_square_size,
      pixel = x + y*custom_icon_square_size;
      decodeRGB(icon_memory[pixel], gfx_r, gfx_g, gfx_b);
    
      gfx_x = floor(origin_x + x*pixel_scale);
      gfx_y = floor(origin_y + y*pixel_scale);
      gfx_rectto(floor(origin_x + (x + 1)*pixel_scale), floor(origin_y + (y + 1)*pixel_scale));
      x += 1;
    );
    y += 1;
  );
  
  prev_editor_drawing = editor_drawing;
  editor_drawing = 0;
  mouse_cap&1 || mouse_cap&2 ? (
    x = floor((mouse_x - origin_x)/pixel_scale);
    y = floor((mouse_y - origin_y)/pixel_scale);
    x >= 0 && y >= 0 && x < custom_icon_square_size && y < custom_icon_square_size ? (
      pixel = x + y*custom_icon_square_size;
      mouse_cap&1 ? (
        icon_memory[pixel] = encodeRGB(editor_r, editor_g, editor_b);
        editor_drawing = 1;
      ) : (
        decodeRGB(icon_memory[pixel], editor_r, editor_g, editor_b);
      );
    );
  );
  prev_editor_drawing && !editor_drawing ? (
    // Mouse-up: trigger an undo step
    sliderchange(-1);
  );
);
function drawColourPicker(origin_x, origin_y, width, height) local(cursor_light, value, channel) (
  gfx_gradrect(origin_x, origin_y, width, ceil(height/3), 0, editor_g, editor_b, 1, 1/width, 0, 0, 0, 0, 0, 0, 0);
  gfx_gradrect(origin_x, floor(origin_y + height/3), width, ceil(height/3), editor_r, 0, editor_b, 1, 0, 1/width, 0, 0, 0, 0, 0, 0);
  gfx_gradrect(origin_x, origin_y + floor(height*2/3), width, ceil(height/3), editor_r, editor_g, 0, 1, 0, 0, 1/width, 0, 0, 0, 0, 0);
  cursor_light = (editor_r + editor_g*2 + editor_b) < 512;
  
  gfx_r = gfx_g = gfx_b = cursor_light ? 1 : 0;
  gfx_a = 1;
  gfx_circle(origin_x + width*editor_r, origin_y + height*1/6, height/12, 1);
  gfx_circle(origin_x + width*editor_g, origin_y + height*3/6, height/12, 1);
  gfx_circle(origin_x + width*editor_b, origin_y + height*5/6, height/12, 1);
  
  mouse_cap&1 ? (
    mouse_x >= origin_x && mouse_x < origin_x + width && mouse_y >= origin_y && mouse_y < origin_y + height ? (
      value = (mouse_x - origin_x)/width;
      channel = floor((mouse_y - origin_y)/height*3);
      channel == 0 ? editor_r = value;
      channel == 1 ? editor_g = value;
      channel == 2 ? editor_b = value;
    );
  );
);

g_current_screen = "drawing-icon";
g_current_icon = 0;

g_current_screen == "drawing-icon" ? (
  g_current_icon_memory = custom_icons + g_current_icon;
  
  drawIconEditor(g_current_icon, 50, 50, 150);
  gfx_r = gfx_g = gfx_b = gfx_a = 1;
  gfx_x = gfx_y = 49;
  gfx_lineto(49, 200);
  gfx_lineto(200, 200);
  gfx_lineto(200, 49);
  gfx_lineto(49, 49);
  drawColourPicker(50, 215, 150, 50);
  
  // TODO: when this screen closes, save to the appropriate off-screen buffer
) : (
  g_x = g_y = 0;
  loop(4,
    loop(4,
      // TODO: draw the off-screen buffers
      0
    );
  );  
);

@serialize

// Detect older presets
serialize_version = 0;
file_var(0, serialize_version);

// Save raw pixels
file_var(0, custom_icon_count);
file_mem(0, custom_icons, custom_icon_count*custom_icon_step);
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-25-2019 at 10:44 AM.
geraintluff is offline   Reply With Quote
Old 06-25-2019, 12:32 PM   #4
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

@geraintluff


Pixel art ? cool :P





--
I wanted to use /data/track_icons folder cause there is already PNG in there. I could indeed hardcore their path, but it would not be very flexible (no way to add custom images), hand having "placeholders" like "customimage15.Png" could be an idea but not very handy from user point of view if he has to rename files.


--
I in fact also brainstorming about how from to handle image to pad mapping from a end user ergonomics point of view.
- having one slider per pad with images link ?
- having one slider per notes with image link (but not very possible cause there is 127 notes ^^)

- Should I handle that with txt files which could contains notes to map with image path ? This can work but not very flexible to edit, not sure the users will do it (though it may be the first best solution to solve all problems).


Maybe this last solution would be the best with the tools we have access. A CSV.txt file with with note number, image.png path relative to the .txt, and optional note name (cause we can't access MIDINoteNames folder either).


Do you think this CSV solution wouldn't be too much trouble ?



Brainstorming.
X-Raym is offline   Reply With Quote
Old 06-25-2019, 01:37 PM   #5
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

My main concern is that I'm not sure whether you can open a PNG file from a string. Audio files, yeah, but I've only used images via "filename:" entries.

Since this is a filesystem-heavy task (which JSFX isn't really designed for), could you go the "companion ReaScript" route? Register a ReaScript for startup (or trigger it manually) which scans the directory and does relatively-simple string replacement to update the "filename:" entries and maybe slider labels? The resulting generated effect could live in the per-project Effects/ directory.

(Also just brainstorming - I'm not a big ReaScripter, so might be completely off-base)
__________________
JSFX set | Bandcamp/SoundCloud/Spotify
geraintluff is offline   Reply With Quote
Old 06-25-2019, 02:20 PM   #6
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Companion script should work to pass file names via Gmem indeed.


But not populating sliders though.


Maybe sliders of PNG is not the way to go.... The .txt CSV seems more appropriate IMHO.
It has the main advantage of not requiring any other script.
X-Raym is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 07:23 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.