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

wav file recorder

DSP related issues, mathematics, processing and techniques

wav file recorder

Postby KG_is_back » Tue Feb 21, 2017 12:32 pm

I've been playing with ruby and made this wave file recorder. It creates a wave file and streams frames directly into it on disk. The CPU hit is rather high though. By default it records in 32bit float mono. 16bit int and 32bit int formats and stereo are semi-supported (the recorder needs modification, but WavFile class supports them).
Attachments
wavfileclass.fsm
(29.02 KiB) Downloaded 1398 times
KG_is_back
 
Posts: 1196
Joined: Tue Oct 22, 2013 5:43 pm
Location: Slovakia

Re: wav file recorder

Postby tulamide » Tue Feb 21, 2017 4:48 pm

Hey KG,

that's a nice start! It was too demanding when I actually tried to record (I'm on a notebook with a 5400 rpm harddrive), but I read the class and it is a simple approach. Now to bring down cpu load it needs several things:
1) Buffering. Instead of trying to write each frame as it happens, keeping several of them in memory and only write at a slower rate is to be preferred. I don't know of any recorder that actually tries to write data at frame rate (all the mechanical restrictions from the drive just doesn't allow that).
2) Trying to get rid of the array conversion of the frame. With Frame's :data, you get access to the memory address of the start of this frame's data. It is in a certain format. Here's an example that makes use of this address: http://www.dsprobotics.com/support/viewtopic.php?f=4&t=3844&hilit=ruby+frame&start=10#p21235
With direct access to the memory block, is there anything within your knowledge of Assembler or DSP, that allows you to save this block directly to disk, without conversion to an array?
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: wav file recorder

Postby tulamide » Tue Feb 21, 2017 5:49 pm

Forgot about this important info. In my fsm, the address of the memory block is converted to a format that the ASM editor uses. So the output is only usable for Assembler! The raw address is available inside the RubyEdit.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany

Re: wav file recorder

Postby KG_is_back » Tue Feb 21, 2017 7:32 pm

I have been experimenting with the address a lot. Assembler in Flowstone does not have capabilities to do system calls - you can't save data from assembler to disc. Hell, you can't even allocate new memory form it.

However, ruby can pass pointers to its binary strings.

Code: Select all
str= "abcdefg"
address=[str].pack("P") #returns new string with 4byte pointer to the contents "str" variable.

address.unpack("P7") #returns first 7 characters from the string to which the address points.

#you can convert the pointer into int or float and output it to flowstone.
#this way you can access the contents of the string in assembler

output address.unpack("L") #converts the address to integer and outputs it to flowstone



In fact, I do believe this is how the Frame class is implemented in flowstone. it has internal string containing the actual data. ".data" method outputs the address of that string, which flowstone then uses in mono-to-frame and frame-to-mono prims to write/read its contents. Evidence of this is, that when you change the implemnentation of data method in frame class, frames no longer work in FS until you restart it (which restores original Frame class implementation).

Only problem is, it works only one way. You can't convert arbitrary address to ruby string object - you get "no associated pointer" exception. This is because ruby handles the actual pointer internally. In the example above,
"address" string object internally holds hidden reference to the original "str" string object (the same kind of reference that is used by ruby garbage collector to free unused objects). When you call the "unpack("P")" method, the method checks if the address in this string matches any object that it internally references. If not, "no associated pointer" error is raised - even if actual string object exists at that address.

Code: Select all
str= "abcdefg"
address=[str].pack("P")

int_address=address.unpack("L") #unpacks the address as a integer
#this integer no longer holds reference to "str" object

copy_of_address=int_address.pack("L") #packs the integer as new string

copy_of_address==address #returns true, because both of these contain the same data

address.unpack("P7") #returns "abcdefg"  - the contents of "str" string, to which it holds hidden reference

copy_of_address.unpack("P7") #raises error, despite the fact it contains address, it doesn't secretly reference matching object.


What this allows us to do is to create string buffer in Ruby, pass its address and address of the frame to assembler. In assembler copy contents of the frame into the buffer. In ruby save the buffer to file. This allows us to skip conversion of frame to array.

However, I think it would be better if we would modify the Frame class. Specifically, we would add some kind of "rawData" method which would return its internal string directly. Unfortunately, it has proven to be easier said than done. Frame.new(n).instance_variables does return empty array, which means the data isn't stored in instance vars. Similarly Frame.constants and Frame.class_variables returns empty array, which means none of the data is actually stored anywhere in the class or its instances. I am trying to find a way to access the referenced objects which would allow me to pinpoint the location of the data.

Another approach would be to rewrite the Frame class entirely from scratch. Assuming what I said above is true, it should be possible to reverse-engineer all methods in the class and then add our own, now knowing where the data is...
KG_is_back
 
Posts: 1196
Joined: Tue Oct 22, 2013 5:43 pm
Location: Slovakia

Re: wav file recorder

Postby tulamide » Wed Feb 22, 2017 1:39 am

A lot of interesting details there, KG!

Messing around with memory is a dangerous thing. That's why Ruby was developed with the decision to keep away all of this from the users. That's fine for the most time, regarding DSP it is a disaster.

I'm not sure that Ruby's Frame is anything more than a wrapper. You have to think about the implementation. Frame is the very last link of the chain. It is 100% identical to the asio/directx/etc buffer. It is the second part of a double buffer. For me that all indicates it is the access to the original buffer as Flowstone uses it and therefore the Frame class accesses some C-function from the FS code for the conversion.

Way easier than trying to reverse engineer, we should ask MyCo if the frame class could be extended with our wishes. If my assumption is correct than it wouldn't be much work. If you are right it might involve more work, but still be worth it.
"There lies the dog buried" (German saying translated literally)
tulamide
 
Posts: 2714
Joined: Sat Jun 21, 2014 2:48 pm
Location: Germany


Return to DSP

Who is online

Users browsing this forum: No registered users and 35 guests