--- Music MP3 Function -- fix CE6.4 MemoryStream write, and add other useful methods if oldcreateMemoryStream==nil then oldcreateMemoryStream = createMemoryStream end function createMemoryStream() local obj = oldcreateMemoryStream() local oldwrite=obj.write obj.write = function (t,n) -- override default write local count=0 for _,v in ipairs(t) do if count==n then break end oldwrite({v},1) count=count+1 end end obj.writeDword = function (v) obj.write(dwordToByteTable(v)) end obj.writeWord = function (v) obj.write(wordToByteTable(v)) end return obj end --convertMP3ToRIFFMP3(stream) function convertMP3ToRIFFMP3(stream) local riffmp3 = createMemoryStream() local header = { 0x46464952,0x00000000,0x45564157,0x20746D66,0x0000001E,0x00020055, 0x0000AC44,0x00000000,0x00000001,0x0001000C,0x00000002,0x00010001, 0x61660571,0x00047463,0x2FF80000,0x61640014 } -- default is 44100Hz , Stereo local rateTable = {[0] = {11025,12000,8000}, --mpeg ver2.5 [2] = {22050,24000,16000}, --mpeg ver2 [3] = {44100,48000,32000}} --mpeg ver1 local bitrateTable = {[1]={32,64,96,128,160,192,224,256,288,320,352,384,416,448}, [2]={32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384}, [3]={32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320}, [4]={32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256}, [5]={ 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}} for i,v in ipairs(header) do riffmp3.writeDword(v) end riffmp3.writeWord(0x6174) riffmp3.writeDword(stream.Size) stream.Position = 0 riffmp3.copyFrom(stream,stream.Size) riffmp3.Position = 0x4; riffmp3.writeDword(stream.Size+0x24) stream.Position = 0 local chunk = stream.read( math.min(65536,stream.Size) ) local DWORD = byteTableToDword( {chunk[4],chunk[3],chunk[2],chunk[1]} ) --[[ looking for MPEG Audio frame header bits 31 through 21 must all be set; Frame sync bit 18 and bit 17, at least one set; Layer bits 15 through 12, at least one clear; bitrate index bits 11 through 10, at least one clear; sample rate index also use above to find a header bit 20 and 19; MPEG audio id bit 7 and 6; channel mode ]] local i=0x1 while (i<=#chunk-4) do if (bAnd(DWORD,0xFFE00000)==0xFFE00000) and (bAnd(DWORD,0x60000)~=0) and (bAnd(DWORD,0xF000)~=0xF000) and (bAnd(DWORD,0xC00)~=0xC00) then --probably MPEG Audio Layer I/II/III frame header local channels =(bAnd(bShr(DWORD, 6), 3) == 3) and 1 or 2 local layer = 3 - bAnd(bShr(DWORD,17), 3) + 1; local mpegaudioid = bAnd(bShr(DWORD,19), 3) local rateindex = bAnd(bShr(DWORD,10), 3) local bitrateindex= bAnd(bShr(DWORD,12),15) local samplerate = rateTable[mpegaudioid][rateindex+1] local row if mpegaudioid==3 then row=layer -- mpeg ver1 elseif layer==1 then row=4 -- mpeg ver2 and ver2.5, Layer 1 else row=5 -- mpeg ver2 and ver2.5, Layer 2 and 3 end local bitrate = bitrateTable[row][bitrateindex] riffmp3.Position = 0x16; riffmp3.writeWord(channels) riffmp3.writeDword(samplerate) riffmp3.writeDword(math.floor(bitrate*1000/8)) break end if (bAnd(DWORD,0xFFFFFF00)==0x49443300) and (bAnd(DWORD,0xFF)<0xFF) --ID3 tag found then local size = bOr(bShl(chunk[i+6],7),chunk[i+7]) size = bOr(bShl(size,7),chunk[i+8]) size = bOr(bShl(size,7),chunk[i+9]) i=i+size end DWORD = bOr( bShl(DWORD,8) , chunk[i+4] ) % 0x100000000 i=i+1 end chunk = nil riffmp3.Position = riffmp3.Size - 1 return riffmp3 end ---- function sound_prepare(track) if track==nil then return nil end if knownStreams==nil then knownStreams = {} end local stream,streamID -- set stream variable if type(track)=='string' then if knownStreams[track]~=nil then return track end -- check name as StreamID if findTableFile(track) then stream=findTableFile(track).Stream else return nil end elseif track.ClassName=='TMemoryStream' then stream=track else stream=track.Stream end streamID=userDataToInteger(stream) if knownStreams[streamID]~=nil then return streamID end stream.Position = 0 if table.concat(stream.read(4),'-')=='82-73-70-70' then -- RIFF format (wave file, etc.) knownStreams[streamID]=stream else -- probably mp3 file, converting -- convertMP3ToRIFFMP3(stream) local riffmp3 = convertMP3ToRIFFMP3(stream) knownStreams[streamID]=riffmp3 end -- if string, use it as streamID too if type(track)=='string' then knownStreams[track]=knownStreams[streamID] end return streamID end if oldplaySound==nil then oldplaySound=playSound end --- function playSound(track, ...) local ID=sound_prepare(track) if ID then oldplaySound(knownStreams[ID], ...) else print('track not found') end end