Go Back   Cockos Incorporated Forums > REAPER Forums > ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum

Reply
 
Thread Tools Display Modes
Old 07-17-2018, 08:25 AM   #1
brainwreck
Human being with feelings
 
Join Date: Jul 2006
Posts: 20,859
Default JSFX: What am I missing, or what is wrong with this wav player example?

I notice in the console that length is 0.

Here is the file that came with the example code: https://app.box.com/s/ty1hznq2flxs7fkmspcjljviyb3pp7rb

Here is the code:

Code:
desc:wav-player

filename:0,test-file.wav
handle = file_open(0);

len=file_avail(handle);
amt=file_mem(handle,offset,len);

file_riff(handle,nch,samplrate);
nch ? file_mem(handle,0,file_avail(0));

@sample

pos = 0;

while(pos < len) (
	spl0 = pos;
	spl1 = pos;
	pos += 1;
);

file_close(0);
__________________
It's time to take a stand against the synthesizer.
brainwreck is offline   Reply With Quote
Old 07-17-2018, 10:29 AM   #2
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

It's nearly right, the file code isn't in a code section so that should go in @init. The playback isn't right and file_close shouldn't be called in every @sample.

You should get familiar with the syntax used to access the giant array of local memory we have in JSFX...
Code:
// access like...
start_position_in_array[offset_from_that_start_position];

blah = 0; // start position
blah[0] = 1; // this is position 0 + 0
blah[2] = 3; // this is position 0 + 2

bling = 100;
bling[0] = 2; // this is position 100 + 0

blah[100]; // this is the same as bling[0] ( 0 + 100 == 100 + 0 )
Here's a working version of your code, hopefully it rings some bells...
Code:
desc:wav-player


@init
  // declare and zero these (not needed in JSFX, but good to do anyway 
  // to keep track of what variables we are using).
  mem_pos = cur_pos = 0;

  handle = file_open("test-file.wav");

  // if our file is a RIFF then num_channels and samplerate will
  // be set here
  file_riff(handle, num_channels, samplerate);

  // remember we have a giant array of memory, so mem_pos is the
  // position in this array that the file contents will be put
  num_channels > 0 ? (
    amt = file_mem(handle, mem_pos, file_avail(handle));
  );

  // we have our samples stored (or not if the above failed) in
  // memory, so close file here
  file_close(handle);


@sample
  // only play when reaper is playing and if valid riff file (amt is positive)
  amt && play_state ? (
    spl0 = mem_pos[cur_pos];
    
    // deal with stereo or mono, ignores extra channels
    num_channels == 2 ? (
      spl1 = mem_pos[cur_pos + 1];
    ) : (
      spl1 = mem_pos[cur_pos];
    );
    
    // increment our position by number of channels or loop back to zero
    // if we've reached the end
    cur_pos += num_channels;
    cur_pos > amt ? cur_pos = 0;
  );

Last edited by snooks; 07-17-2018 at 02:15 PM. Reason: fixes bug
snooks is offline   Reply With Quote
Old 07-17-2018, 10:41 AM   #3
brainwreck
Human being with feelings
 
Join Date: Jul 2006
Posts: 20,859
Default

snooks, many many thanks! It's going to take me some time to look this over, and I'm just about out of free time today. But I loaded up your example, and it works over here. By the way, the code that I posted is from a directory of example scripts, and I have no idea where they came from. I think I was headed in the right path at least, reading up on jsfx's array just before you posted back.
__________________
It's time to take a stand against the synthesizer.
brainwreck is offline   Reply With Quote
Old 07-17-2018, 01:55 PM   #4
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

No problemo, I edited the post to fix a small bug with the sample playback where it would play one sample of zero (or whatever was at the next positions after the file) at the end of every loop.

Btw I'm sometimes kind of crappy at explaining things, so if that happens please tell me and I'll try from a different angle.
snooks is offline   Reply With Quote
Old 07-18-2018, 09:32 AM   #5
brainwreck
Human being with feelings
 
Join Date: Jul 2006
Posts: 20,859
Default

Snooks, I think you do well in your explanations at taking into consideration a noob persepective.

I'm jumping back and forth between the example code that I posted and your new code (with nice explanations) to try and understand why the example code failed.

Question #1: In the example code (and the example from the jsfx reference), filename:0,test-file.wav is used. In what section should that line have been placed? It seems ok before any code sections, but it doesn't work in @init or elsewhere. But if it is placed before any code section, handle value is 1, and the jsfx reference doesn't say what a value of 1 means. I had assumed that 1 == passed. If it is placed in @init, handle is 0 and the compiler complains about the syntax. The jsfx reference says that when file_open() fails, it will return a value < 0, usually -1. Your code returns -1 for it's use of file_open(), but it couldn't have failed, since the code works. So then, filename:0,test-file.wav seems impossible to use, and the reference on file_open() doesn't seem to jive with what I am seeing in the console.

Here is what the reference says about filename:N,some-file:
Quote:
filename:0,filename.wav
These lines can be used to specify filenames which can be used by code later. These definitions include 0 (the index) and a filename. The indices must be listed in order without gaps -- i.e. the first should always be 0, the second (if any) always should be 1, and so on.

To use for generic data files, the files should be located in the REAPER\Data directory, and these can be opened with file_open(), passing the filename index.
And here is what the jsfx reference says on file_open():

Quote:
If file_open() fails, it will return < 0 (usually -1).
__________________
It's time to take a stand against the synthesizer.

Last edited by brainwreck; 07-18-2018 at 09:40 AM.
brainwreck is offline   Reply With Quote
Old 07-18-2018, 02:56 PM   #6
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

Yes, the filename:0,blah.wav should be before the @code sections, but it's more direct to use the newer string parameter so I changed it to that.

handle appears to be -1 because it returns to that value after the file has been closed and it's only opened for a tiny fraction of a second, where it is indeed 1. The behaviour of handle here might seem weird (because we didn't change it), but it's because behind the scenes in C world it's passed as a pointer which means once we give it to file_open, JSFX stores it's location (not just value) in the background and so can alter its value in file_close without us touching it.

You can uncomment the file_close call to see it stay at a positive value (which increments on every playback since the last file handle won't be getting closed).
snooks is offline   Reply With Quote
Old 07-19-2018, 06:43 AM   #7
brainwreck
Human being with feelings
 
Join Date: Jul 2006
Posts: 20,859
Default

Thanks again, snooks. That probably should have been very obvious, and I'm swimming in my noobness on this stuff. The only thing left in your code that I'm shaky on is:

Code:
spl1 = mem_pos[cur_pos + 1];
and

Code:
cur_pos += num_channels;
Question #2: I guess what I don't know here is how the sample data is structured. According to your code, it seems that the sample data is interleaved such that a channel 1 byte word immediately follows a channel 0 byte word, continuing in this fashion. Is that right?
__________________
It's time to take a stand against the synthesizer.

Last edited by brainwreck; 07-19-2018 at 08:27 AM.
brainwreck is offline   Reply With Quote
Old 07-19-2018, 07:32 AM   #8
brainwreck
Human being with feelings
 
Join Date: Jul 2006
Posts: 20,859
Default

If anyone knows of a good noob resource for learning about wav and riff, I would be grateful for a link.
__________________
It's time to take a stand against the synthesizer.
brainwreck is offline   Reply With Quote
Old 07-19-2018, 09:26 AM   #9
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

Yes, you are understanding perfectly!

Re wav files in general, there a bit of help happening in the background here too, because calls to file_avail and file_mem don't return the size of the file in bytes, but the total number of samples on each channel added together. file_mem doesn't write the whole file to memory either, it skips the header and just writes the samples.

So parsing of the wav file is done for us automagically. This might be causing a bit of confusion if you are thinking in terms of raw files.

You are correct in saying that the file_mem call leaves us with a series of interleaved sample values written to memory. If there's two channels we get the sample at current_position for the left channel then current_position + 1 for the right channel, then we increment current_position by the number of channels so that it points at the first channel of the next pair of samples when @sample is called next.
snooks is offline   Reply With Quote
Old 07-19-2018, 10:22 AM   #10
brainwreck
Human being with feelings
 
Join Date: Jul 2006
Posts: 20,859
Default

Excellent explanations on this stuff, snooks. Again, many thanks! I think I wouldn't have gotten to this point without all your help.
__________________
It's time to take a stand against the synthesizer.
brainwreck is offline   Reply With Quote
Old 07-19-2018, 12:35 PM   #11
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

No worries brainwreck, Tale held my hand a couple of usernames ago so it's all just recycled karma.
snooks is offline   Reply With Quote
Old 05-09-2021, 03:58 AM   #12
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 2,643
Default

Just trying to work out file_riff in JSFX, I want to be able to play a section of a wav file in sync to Reaper.
If I set cur_pos to 352800 (2 * 176400) in the script I found it will play from bar 3 but I have to set Reaper bpm to 130.5 to play the 120bpm wav close to sync.
I don't know if I could use RubberBand Audio library to stretch the source wav to Reaper's bpm as I want to use the JSFX with ReaPlugs reajs.dll?
https://breakfastquay.com/rubberband/
https://github.com/breakfastquay/rubberband
I would like to be able to get it to play a set section of the wav at a particular bar in Reaper.
So say I want to play from bar 4 in the wav for 2 bars at bar 8 in Reaper.
I have Drums120bpm.wav in C:/Temp

Code:
desc:wav-player


@init
  // declare and zero these (not needed in JSFX, but good to do anyway 
  // to keep track of what variables we are using).
  // mem_pos = cur_pos = 0;
  mem_pos = 0; 
  cur_pos = 352800;
 
  handle = file_open("C:/Temp/Drums120bpm.wav");

  // if our file is a RIFF then num_channels and samplerate will
  // be set here
  file_riff(handle, num_channels, samplerate);

  // remember we have a giant array of memory, so mem_pos is the
  // position in this array that the file contents will be put
  num_channels > 0 ? (
    amt = file_mem(handle, mem_pos, file_avail(handle));
  );

  // we have our samples stored (or not if the above failed) in
  // memory, so close file here
  file_close(handle);


@sample
  // only play when reaper is playing and if valid riff file (amt is positive)
  amt && play_state ? (
    spl0 = mem_pos[cur_pos];
    
    // deal with stereo or mono, ignores extra channels
    num_channels == 2 ? (
      spl1 = mem_pos[cur_pos + 1];
    ) : (
      spl1 = mem_pos[cur_pos];
    );
    
    // increment our position by number of channels or loop back to zero
    // if we've reached the end
    cur_pos += num_channels;
    cur_pos > amt ? cur_pos = 0;
  );
__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
STASH Downloads https://stash.reaper.fm/u/ReaTrak
MusoBob is offline   Reply With Quote
Old 05-09-2021, 04:41 AM   #13
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 2,643
Default

The trouble now is file_riff plays in Reaper but not in the reajsVST !!
So maybe there's another way to play local files in JSFX reajsVST ?
__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
STASH Downloads https://stash.reaper.fm/u/ReaTrak
MusoBob 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 01:03 PM.


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