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
5 posts
• Page 1 of 1
wav file recorder
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
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?
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
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
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.
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.
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...
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
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.
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
5 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 42 guests