Hi,
I will admit that my understanding of both ACM drivers as well as the os x audio libraries are not perfect and mostly come from work on this code itself. So i will fully admit it is most likely full of areas needing improvement.
Kristofer Henriksson wrote:
Aric,
I may have been operating under some faulty assumptions. I thought that all mp3 files would "begin at the beginning" and also keep track of how much of the source data the convert function said that it used. I am very careful to set the value of *nsrc to agree with how much source data was successfully used and assume that the calling function with resend the data that is not used. If this is done, it ensures a valid frame at the start of each invocation.
Yes, a proper application should do just that. It should be tracking the value in nsrc and resend unused data at the beginning of the next buffer.
You get a lot of the expected source stream format from MPEG3_StreamOpen. With that i wonder if the presence of an ID3 tag becomes optional. My familiarity with mp3 format makes me unsure if a packet header would also be required.
As far as using AudioFileStream, I tried for a bit to get it to work before I wrote my own custom mp3 parser. I'm running Snow Leopard (10.6.3) and never got the background music to work in Oblivion. One of the problems is that Mp3AudioConverterComplexInputDataProc needs to return an error if it will have more data in the future, rather than returning zero. However, even changing this, AudioFileStream seemed to be skipping a lot of mp3 frames.
The lack of an error in that return is probably an oversight on my part. All the mp3 clips in the game i was working with where sent in one piece so there was only one pass through the loop that consumed all of the data. I am unsure why skipping mp3 frames would occure. My guess is that I am feeding the data in incorrectly and on those boundries between feeds frames are being ignored/corrupted or the like.
If you tell me what are more appropriate assumptions I should be making in my parser, I can fix it to work the way it should. I suppose I am also assuming that it will usually receive at least one full packet, and if this is unjustified I can fix this as well. If I should expect calling functions to ignore the value of *nsrc, then I can just implement an internal single-packet buffer, and this should take care of the problem.
I think the assumptions we need to investigate is the one about there being a packet header at the beginning. Maybe for non variable bit rate mp3s we just get the data given to us when the stream is opened.
In fact, going on a hunch i just got your code to work great with my game!
What i did was this:
I added PACMDRVSTREAMINSTANCE adsi to Mp3GetPacketLength and then when you would return -1 if you could not determin the header I instead returned (192000 * 144) / adsi->pwfxDst->nSamplesPerSec.
I picked that because it shows up in other areas of the code where we need to get a length.
This is exciting also because there where a few mp3s that whre returning 'Fmt?' errors from the stream code and would not play. But with your patch and this change those clips played as well.
Does that give you something to work with? You clearly understand mp3 format better than I.
-aric