Why you want to support AIFF, isn’t it a purely outdated container format nowadays? For example, there is M4A.
For a very specific use case, I have an OP-1 and it only works with the AIFF format + custom header with sample slice points etc.
I want to make an XRNI to AIFF convertor with slice points & tunings that will load into the OP-1 with these preserved, lets me create sample packs, building blocks that I can jam with in OP-1…
Looks like much of the leg work and techniques have already been cracked by mxb in the file imports toolbut much of this is on stuff I have little knowledge about e.g. binary files, LSB, MSB, 2s complements etc. Could probably figure it all out given enough time, but I’m looking for a shortcut
I assume afta8 you mean the ‘generating_aiff’ function? Quickly looking that audiodata parameter seems to want to be a char string of the sample data. I think first you would have to convert normalised -1 +1 renoise sample_buffer data to say 8-bit (or 16-bit) signed sample data into a table, then convert the table to a string for the audiodata parameter.
Thanks 4Tey, that helps, I presume ‘signed sample data’ is the same as PCM data?
Not sure how to convert -1 to +1 values into this, but will research it… Also I presume Renoise is doing this anyway when saving out as wav… maybe there is a shortcut by saving out the Wav file using the API and then stripping the PCM data out of that…
Yes possibly (although don’t quote me on it :D) linear PCM is signed sample data and yes you could recompose/hack a saved wav file sample data from renoise into a aiff file afta8
(But looking from a purely scripting point of view…) Note, quickly looking at the file format(s) you posted afta8 you would have to keep in mind that the function mxb shows gives you a basic aiff file. You would have to modify that function to also output a modified COMM chunk and output a APPL chunk into the file to accommodate for the parameters to the OP-1.
You would have to modify that function to also output a modified COMM chunk and output a APPL chunk into the file to accommodate for the parameters to the OP-1.
Yes, you are right in that, I am hoping that once I have figured out how to create a basic AIFF file, I can hack mxb’s code to do the extra header with a bit of trial and error and a hex editor.
I have the samples generated by the OP-1 to compare against so comparing against these I could do it… but then I could be wrong
Not that you can really go by this afta8 as this is stupid crude, but I managed to get mxb’s function to save out a aiff file with a mono 16-bit 44100Hz sample with:
local data = {}
local nf = renoise.song().selected_instrument:sample(1).sample_buffer.number_of_frames
local dptr = 0
for n=1,nf do
local SampNumber = renoise.song().selected_instrument:sample(1).sample_buffer:sample_data(1,n)
if SampNumber < 0 then
SampNumber = 65536 - (SampNumber * -1) * 32768
else
SampNumber = SampNumber * 32768
end
data[dptr] = string.char(bit.band(SampNumber,0xff))
dptr = dptr + 1
data[dptr] = string.char(bit.rshift(SampNumber,8))
dptr = dptr + 1
end
generate_aiff(1,44100,16,table.concat(data))
Nah, afta8 the bitwise operations is just a way of shifting the bits down and masking bits to output the low-byte/high byte of a 16-bit number into two 8-bit chars. Nothing to do with any audio degradation. The lines you would be most interested in are these:
if SampNumber < 0 then
SampNumber = 65536 - (SampNumber * -1) * 32768
else
SampNumber = SampNumber * 32768
end
That’s just a silly hack up from me. There is probably a better way of converting a normalised signed -1…+1 floating point sample into a signed 16-bit integer number. If there is any ‘degradation’ it is going to be here. I’m sure afta8 you can come up with a lot better way
Ah ok, I get it now, so any errors creeping in will be from the Integer to Float conversion. I suppose the simplest way to test this would be to do a null test with a source wav and the exported aiff.
I will test your code out tonight, but either way its enough to get me going on writing the custom headers. Thanks again
If there is any ‘degradation’ it is going to be here.
After testing that code and doing a null test, it does introduce noise. Not sure how to fix this, I’m guessing some kind of dither… lua uses doubles for everything which is 64bit I think…
The final aiff output is 16bit so the introduced noise is probably down to bit rate conversion I think, don’t really fancy writing a dither algorithm in lua
Hmm, interesting afta8. Not sure about dithering/noise algos, but I’ve done a little binary compare test myself. I took a simple 16-bit 44100Hz mono sample.
Asked Renoise to produce a wav file from this and extracted the 16-bit linear PCM sample data. I then ran through my above code to produce a aiff file and extracted the PCM linear data from that file. We are talking a sample size of 19810(bytes) / 2 = 9905 16-bit word size samples. Then I binary compared the two files. They are 100% identical. Now I’m not saying that that is conclusive in any way afta8. I suppose at the moment what I could possibly conclude is that if there is a rounding/error factor creeping in at some point, it is very small between that and a Renoise wav file?
I’m not comparing the binary files just testing with a Sine wave and loading them in Renoise (it will import aiffs) and can hear audible noise on the aiff version… see the attached files.
I’m using your code exactly as above, also attached the tool file if you want to have a look (it will add an aiff export option to the tools menu) - are you on mac or windows?
Ah, more interesting afta8 Yes I can see the ‘noise’ here. I admit it is a little interesting. I tend to use Linux btw (well it had to be one of the two afta8 :D) The first thought I’m thinking here is to convert that ‘sine_wav_original’ file you have there to a aiff file via a 3rd party program. I’m just thinking if the unix program ‘sox’ could do this.
Ha, well mac is sort of linux :D… I used Audacity to convert to aiff and it is much better… it doesn’t null perfectly but is good enough… see attached…
Yeah, quite interesting and I’m learning more about binary stuff so all good overall
I got sox to give me a aiff file as well, so at the moment I’ve just spent sometime looking at the two binary files produced. Quickly though I don’t think the header file that mxb’s function produces is quite right (well according to sox anyway…) But that isn’t the full problem. In fact the problem looks kinda strange at the moment, but I’ve got to leave it here afta8. But I will have a look tomorrow at this and see if I can find anything more
Ah okay I think I’ve worked out what it was afta8 I’ve attached a modified version for you, it should now produce your sine wave (without the noise! ) Basically it was the ‘endiness’ of the 16-bit word was the wrong way around. Also I forgot that lua is 1-based indexed on its tables whereas I was thinking in C terms (0-based arrays), so it was missing the first sample of data :rolleyes: I’ve corrected that. The other thing afta8 is that save_aiff function is at the moment hard wired to only work on instrument 0, but you can modify that with the selected instrument number etc… So give that a go afta8 and see if that is a bit better
Also you mention ‘endiness’ and on the wikipedia page for aiff https://en.wikipedia.org/wiki/Audio_Interchange_File_Format itsays “With the development of theMac OS Xoperating system, Apple created a new type of AIFF which is, in effect, an alternativelittle-endianbyte order format.”- Therefore is your code here creating a 'little-endian" format of the aiff?
Could a cdp process help with converting to .aiff? Like;
Yes and could also use sox, however that is only half of what I need to do, the next bit is to ‘customise’ the meta data in the sample to include slice data and tunings, this is why it is better to try and use mxb’s code as it is already writing metadata and hopefully will be easier to modify.
Anyway 4Tey has worked some magic here to help me on my way