Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Implementing Lua Scripting To Creating CE Mp3 Player

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials -> LUA Tutorials
View previous topic :: View next topic  
Author Message
Corroder
Grandmaster Cheater Supreme
Reputation: 75

Joined: 10 Apr 2015
Posts: 1668

PostPosted: Sat Mar 03, 2018 2:17 am    Post subject: Implementing Lua Scripting To Creating CE Mp3 Player This post has 3 review(s) Reply with quote

In connection to these topics :

http://forum.cheatengine.org/viewtopic.php?t=584021
http://forum.cheatengine.org/viewtopic.php?t=606901

which already answerd by the 'play MP3 sound in CE function' creator : mgr.inz.Player
as also knew as ones most respected Cheat Engine / CEF users.

So, the fisrt thing I want to do is to thank so much to mgr.inz.Player and also Dark Byte as
Cheat Engine creator.

Form those topics above, I have created a 'Simple MP3 Player' by followed 'play MP3 sound in CE function'
including added and modified some functions and use pure Cheat Engine Lua scripting.
My goal by doing this project is for learning purpose and more than it is to prove and show if CE not only use
for memory hacking, it also can use for other purpose, specially for Lua scripting.

The project as below :

--================================================================--
-- Project name : CRDR-MP3Player-Ver.4.0
-- Creator : Corroder a.k.a VCLBro
-- Created date : 28-02-2018
-- Scripting Language : Lua 5.3 compatible Lua 5.1, Lua 5.2
-- Scripting IDE : CE 6.7 Lua Engine
-- Special thanks to : mgr.inz.Player, Dark Byte, CEF Members
-- Purpose : Learning, show CE not only use for hack
--================================================================--
-- Note :
-- 1.All Form GUI on this project made use Lua Scripting
-- 2.GUI Images and Icons, has store as stream files
-- 3.Some notes has added inside script code for references
-- 4.NOT FOR COMMERCIAL USE
--================================================================--

What inside this project ? :

A. Work with Lua Table

1.Function to save and load lua table to a file

Code:
do
local function exportstring( s )
 s = string.format( "%q",s )
 s = string.gsub( s,"\\\n","\\n" )
 s = string.gsub( s,"\r","\\r" )
 s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
 return s
end

function table.save(  tbl,filename )
 local charS,charE = "   ","\n"
 local file,err
 if not filename then
 file =  { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
 charS,charE = "",""
 elseif filename == true or filename == 1 then
 charS,charE,file = "","",io.tmpfile()
 else
 file,err = io.open( filename, "w" )
 if err then return _,err end
 end
 local tables,lookup = { tbl },{ [tbl] = 1 }
 file:write( "return {"..charE )
 for idx,t in ipairs( tables ) do
 if filename and filename ~= true and filename ~= 1 then
 file:write( "-- Table: {"..idx.."}"..charE )
 end
 file:write( "{"..charE )
 local thandled = {}
 for i,v in ipairs( t ) do
 thandled[i] = true
 if type( v ) ~= "userdata" then
 if type( v ) == "table" then
 if not lookup[v] then
 table.insert( tables, v )
 lookup[v] = #tables
 end
 file:write( charS.."{"..lookup[v].."},"..charE )
 elseif type( v ) == "function" then
 file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
 else
 local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
 file:write(  charS..value..","..charE )
 end
 end
 end
 for i,v in pairs( t ) do
 if (not thandled[i]) and type( v ) ~= "userdata" then
 if type( i ) == "table" then
 if not lookup[i] then
 table.insert( tables,i )
 lookup[i] = #tables
 end
 file:write( charS.."[{"..lookup[i].."}]=" )
 else
 local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
 file:write( charS..index.."=" )
 end
 if type( v ) == "table" then
 if not lookup[v] then
 table.insert( tables,v )
 lookup[v] = #tables
 end
 file:write( "{"..lookup[v].."},"..charE )
 elseif type( v ) == "function" then
 file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
 else
 local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
 file:write( value..","..charE )
 end
 end
 end
 file:write( "},"..charE )
 end
 file:write( "}" )
 if not filename then
 return file.str.."--|"
 elseif filename == true or filename == 1 then
 file:seek ( "set" )
 return file:read( "*a" ).."--|"
 else
 file:close()
 return 1
 end
end

function table.load( sfile )
 local tables, err, _
 if string.sub( sfile,-3,-1 ) == "--|" then
 tables,err = loadstring( sfile )
 else
 tables,err = loadfile( sfile )
 end
 if err then return _,err
 end
 tables = tables()
 for idx = 1,#tables do
 local tolinkv,tolinki = {},{}
 for i,v in pairs( tables[idx] ) do
 if type( v ) == "table" and tables[v[1]] then
 table.insert( tolinkv,{ i,tables[v[1]] } )
 end
 if type( i ) == "table" and tables[i[1]] then
 table.insert( tolinki,{ i,tables[i[1]] } )
 end
 end
 for _,v in ipairs( tolinkv ) do
 tables[idx][v[1]] = v[2]
 end
 for _,v in ipairs( tolinki ) do
 tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
 end
 end
 return tables[1]
 end
end



2.Get a table length

Code:
function tablelength(T)
 local count = 0
 for _ in pairs(T) do count = count + 1 end
 return count
end



3.Clearing / empty a table

Code:
function clearTable(tb)
 for i, v in pairs(tb) do
 tb[i] = nil
 end
end
-- [table] = {} also use to clear a table, but in fact with this function but in fact the table still store a nil value



B. Function to convert seconds to time format HH:MM:SS or 00:00:00

Code:
function SecondsToClock(seconds)
 local seconds = tonumber(seconds)
 if seconds <= 0 then
 return "00:00:00";
 else
 hours = string.format("%02.f", math.floor(seconds/3600));
 mins = string.format("%02.f", math.floor(seconds/60 - (hours*60)));
 secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60));
 return hours..":"..mins..":"..secs
 end
end



C. Other functions or and logics to create custom GUI, etc

What about this CRDR-MP3Player-Ver.4.0 player ?
1. Common mp3 player functions : Play, Stop, Resume, Pause
2. Added : Mute / Un-mute volume
3. Added : Filtering mp3 files when browsing on PC/Extrnal storage
4. Added : Created mp3 songs playlist which editable and save
5. Added : Automatic load last saved songs playlist
6. Added : Option to play single song or play songs shuffle
7. Added : Song info when playing -> Title, Path, Duration, File Size
8. Added : Song play elapsed time with custom progress bar
9. Added : MP3 player skin theme selector
10. Added : Loud speaker control -> Balance, Left/Right Volume, Bass/Treble Volume

On future update (plan) :
- Added 'media seek = fast forward / back'
- Added 'sound visualization'

Download Source Code (CT file) :

https://mega.nz/#!Xw8FVZAB!cUOGWWogAvdB5Xxv8XzgSCZcfJDiYVV7Y6JZUPHqQSs

NOTE 2 :
This project is not perfect, it's possible contain some error (I hope not). Anyhow, if you think you can create better then goes on,
then use this project as your motivation.
Even I can do same thing like this using other programming language such as VB, C++ and others but
the main purpose from this project is to prove and show if CE is not iuse for hacking only.
It's more than it if on right hands...


EDIT : 18/03/2018
CRDR-MP3 Player V.5
https://youtu.be/pwBsDrFQEic

Download source code / CT file CRDR-MP3-Player-V5:
https://mega.nz/#!jtkjmQ7Z!_DC-ri1R_CEMQN-mkTBgzH1celOtwBf97GMrxZ_Nc8c


Also if you want play MIDI file format, add this :

Code:
function playMID(path) 
 if not initializeMP3Player() then return end
 MP3PlayerSendCommand('close midifile')
 MP3PlayerSendCommand(string.format('open "%s" type sequencer alias midifile',path))
 MP3PlayerSendCommand('play midifile')
end


To play WMA file format (example with openDialog to locate wma file)

Code:
function playWMA() -- work
 if not initializeMP3Player() then return end
 load_dialog = createOpenDialog(self)
 load_dialog.InitalDir = os.getenv('%USERPROFILE%')
-- load_dialog.Filter = 'MP3 files|*.mp3|*'
 load_dialog.Filter = 'Audio files|*.mp3;*.mid;*.wav;*.wma|Mp3 files (*.mp3)|*.MP3|Mid files (*.mid)|*.MID|Wav files (*.wav)|*.WAV|Wma files (*.wma)|*.WMA|*'
 load_dialog.execute()
 local file = load_dialog.FileName
 s_file = string.sub(file, -4)
 print(s_file)
 if s_file == '.wma' then
 MP3PlayerSendCommand('play '..file)
 else
 print('not WMA file...')
 end
end


Cheers...
Corroder

_________________
Stealing Code From Stolen Code...
And Admit It.. Hmmm....Typically LOL


Last edited by Corroder on Thu Mar 15, 2018 4:01 am; edited 3 times in total
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sat Mar 03, 2018 8:03 am    Post subject: Reply with quote

Nice work, original work. Congratulations.
still foreign to me a lot of coding.
I guess I'm used to 'UDF1' coding.
'CreateTable' is an encoding I still can not figure out.
It also opens and the sliding menu is great. You do it for the 2nd time.
I noticed something;
Still does not install multiple song list.
Songs single, single loading.
A file, 'Ctrl + A' or list selection can not be made. Wink
Without changing any letters in this file,
By registering as a trainer,
Do we have a chance to open it in another trainer?
The writer's identity and identity are present,
there is no need to make a new table.
It will be more accurate to present original articles and works to members.
'AddFile' with this file, we will apply your previous coding?

Thanks @Corroder.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sat May 16, 2020 9:37 am    Post subject: Reply with quote

@Corroder, MP3 code, if it returns to the beginning,
(In simple MP3 player mode)
Can we add and use "findTableFile" to the table without "TrainerOrigin"?
MP3 files will be in the table (add file).
How should we code to execute from table memory?

This code did not work;


Code:
local mp3File9 = findTableFile('music111.mp3').Stream

playMP3(mp3File9)


Is there a solution?

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Corroder
Grandmaster Cheater Supreme
Reputation: 75

Joined: 10 Apr 2015
Posts: 1668

PostPosted: Sat May 16, 2020 11:51 am    Post subject: Reply with quote

I think not to use mciSendString, but use memoryStream.

Example:

Code:
--- Music MP3 Function
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]} )

  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
  knownStreams[streamID]=stream
  else
  local riffmp3 = convertMP3ToRIFFMP3(stream)
  knownStreams[streamID]=riffmp3
  end
 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

--- Test play
file = findTableFile('test.mp3')
playSound(file)

--- Stop play
file = findTableFile('silence.mp3')  -- find somewhere a file with name silence.mp3 which produce no sound
playSound(file)

_________________
Stealing Code From Stolen Code...
And Admit It.. Hmmm....Typically LOL
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sat May 16, 2020 2:42 pm    Post subject: Reply with quote

Corroder wrote:
I think not to use mciSendString, but use memoryStream.



Yes, I have the same code at the moment and "playSound" does not run 2 mp3s at the same time.
I guess it is not possible to play 5 different sounds at the same time.
I tried with playSound and playMP3, it didn't.
I think I should copy 5 "winmm.dll". Smile

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Corroder
Grandmaster Cheater Supreme
Reputation: 75

Joined: 10 Apr 2015
Posts: 1668

PostPosted: Sat May 16, 2020 3:46 pm    Post subject: This post has 1 review(s) Reply with quote

Aylin wrote:
I think I should copy 5 "winmm.dll". Smile


No you dont. If the songs are on local disk (not table file), use mciSendString like this :

Code:
function playMulti(song1, song2,...)
 if not initializeMP3Player() then return end
 local fileName
 fileName = song1
 MP3PlayerSendCommand("open "..fileName.." type mpegvideo alias FirstSound", 0, 0, 0)
 MP3PlayerSendCommand("play FirstSound", 0, 0, 0)

 fileName = song2
 MP3PlayerSendCommand("open "..fileName.." type mpegvideo alias SecondSound", 0, 0, 0)
 MP3PlayerSendCommand("play SecondSound",0, 0, 0)

 -- add here until filename = song5

end

s1 = "E:\\test1.mp3"
s2 = "E:\\test2.mp3"
playMulti(s1,s2)



EDIT:
If your song2 are on table file then you need to find them and save as local files on temporary dir. and then play the sounds from there.
And when then delete them all when the trainer closes. As usual, we did.

_________________
Stealing Code From Stolen Code...
And Admit It.. Hmmm....Typically LOL
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sun May 17, 2020 6:49 am    Post subject: Reply with quote

Sorry, it didn't work.
Also, 5 different songs are not in one command.
So there are 17 songs (or audio files) and they are all on separate buttons.
For example; I am trying to add effects to a music.
Commands should not be together, they should work on separate buttons.
Whenever I run it, it turns off the current sound and works. This shouldn't happen.
When I disable this code, the sound does not play at all.

Code:
  --MP3PlayerSendCommand('close MediaFile')
  MP3PlayerSendCommand( string.format('open "%s" type mpegvideo alias MediaFile',path) )
  MP3PlayerSendCommand('play MediaFile')


I think the following example is enough to understand;
Like a Karoeke,
When playing music, add sound to it. Smile

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Corroder
Grandmaster Cheater Supreme
Reputation: 75

Joined: 10 Apr 2015
Posts: 1668

PostPosted: Sun May 17, 2020 7:07 am    Post subject: Reply with quote

For me this is work. I note you said 'play sound at the same time'.

Code:
function initializeMP3Player()
  if initializeMP3Player_done then return true end

local script64bit=[[loadlibrary(C:\Windows\System32\winmm.dll)
alloc(SimpleMp3Player,4096)
registersymbol(SimpleMp3Player)

SimpleMp3Player:
lea rsp,[rsp-28]
lea rsi,[rcx+400]

lea rdx,[rcx+300]
mov r8d,80
xor r9d,r9d
call mciSendStringW
mov rcx,rax
mov rdx,rsi
mov r8,200
call mciGetErrorStringW

lea rsp,[rsp+28]
ret]]

local script32bit=[[loadlibrary(C:\Windows\System32\winmm.dll)
alloc(SimpleMp3Player,4096)
registersymbol(SimpleMp3Player)

SimpleMp3Player:
push ebp
mov ebp,esp
push ebx

mov ebx,[ebp+8]

sub esp,10
mov [esp],ebx
lea ebx,[ebx+300]
mov [esp+4],ebx
mov [esp+8],80
mov [esp+c],0
call mciSendStringW

mov ebx,[ebp+8]
lea ebx,[ebx+400]

sub esp,0c
mov [esp],eax
mov [esp+0x4],ebx
mov [esp+0x8],200
call mciGetErrorStringW

pop ebx
leave
ret 004]]

  if cheatEngineIs64Bit() then script = script64bit else script = script32bit end
  if autoAssemble(script,true)
  then
    initializeMP3Player_done = true
    MP3PlayerCommandMS = createMemoryStream()
    MP3PlayerCommandMS.Size = 2048
    return true
  else
    return false
  end
end

function MP3PlayerSendCommand(command)
  writeStringLocal(MP3PlayerCommandMS.Memory, command, true)
  writeBytesLocal (MP3PlayerCommandMS.Memory+2*#command, 0, 0)
  executeCodeLocal('SimpleMp3Player',MP3PlayerCommandMS.Memory)
  return readStringLocal(MP3PlayerCommandMS.Memory+1024,512,true),
         readStringLocal(MP3PlayerCommandMS.Memory+768,128,true)
end

function playMP3(path)
  if not initializeMP3Player() then return end
  MP3PlayerSendCommand('close MediaFile')
  MP3PlayerSendCommand( string.format('open "%s" type mpegvideo alias MediaFile',path) )
  MP3PlayerSendCommand('play MediaFile')
end

function playMulti(song1, song2,...)
 if not initializeMP3Player() then return end
 local fileName
 fileName = song1
 MP3PlayerSendCommand("open "..fileName.." type mpegvideo alias FirstSound", 0, 0, 0)
 MP3PlayerSendCommand("play FirstSound", 0, 0, 0)

 fileName = song2
 MP3PlayerSendCommand("open "..fileName.." type mpegvideo alias SecondSound", 0, 0, 0)
 MP3PlayerSendCommand("play SecondSound",0, 0, 0)
end

----- Test, change song files with your own
s1 = "E:\\test1.mp3"
s2 = "E:\\test2.mp3"
playMulti(s1,s2)




And here my old file with song list on a combobox.

Code:
getLuaEngine().cbShowOnPrint.Checked=false
getLuaEngine().hide()

function loadTableCode(n)
 local t = findTableFile(n)
 if t ~= nil then
 local s = t.Stream
 local c = readStringLocal(s.Memory,s.Size)
 return c ~= nil and loadstring(c) -- return a function
 end
end
--
local f = loadTableCode('plsound.lua')
print(type(f))
if type(f) == 'function' then f() else print('not loaded') end

local Mform = createForm()
Mform.Width = 280
Mform.Height = 180
Mform.Position = 'poScreenCenter'
Mform.BorderStyle = 'bsNone'
Mform.Color = '0x00595959'
Mform.Name = 'Mform'

local TitlePanel = createPanel(Mform)
TitlePanel.Left = 1
TitlePanel.Top = 1
TitlePanel.Height = 30
TitlePanel.Width = Mform.Width - 1
TitlePanel.Caption = ' '
TitlePanel.BavelInner = 'bvRaised'
TitlePanel.BavelOuter = 'bvRaised'
TitlePanel.Color = '0x00DFF7FF'  --'0x00868686'
TitlePanel.Name = 'TitlePanel'
TitlePanel.OnMouseDown = function() Mform.DragNow() end

local TitleLabel = createLabel(TitlePanel)
TitleLabel.Left = 10
TitleLabel.Top = 7
TitleLabel.Font.Name = 'Armalite Rifle'
TitleLabel.Font.Style = 'fsBold'
TitleLabel.Font.Size = '12'
TitleLabel.Font.Color = '0x00595959'
TitleLabel.Caption = 'MP3 Song - Player'
TitleLabel.Name = 'TitleLabel'

local SongBox = createComboBox(Mform)
SongBox.Top = TitlePanel.Top + TitlePanel.Height + 10
SongBox.Left = 10
SongBox.Width = Mform.Width - SongBox.Left - 10
SongBox.Color = '0x00DFF7FF'
SongBox.Style = 'csDropDown'
SongBox.Text = 'Pick a song..'
SongBox.Name = 'SongBox'

MsLabel = createLabel(Mform)
MsLabel.Left = 10
MsLabel.Top = SongBox.Top + SongBox.Height + 10
MsLabel.Font.Name = 'Arial'
MsLabel.Font.Size = 9
MsLabel.AutoSize = false
MsLabel.Width = Mform.Width - MsLabel.Left - 10
MsLabel.Height = 50
MsLabel.WordWrap = true
MsLabel.Font.Style = 'fsBold'
MsLabel.Font.Color = '0x00DFF7FF'
MsLabel.Caption = 'Idle..'
MsLabel.Name = 'MsLabel'

items = combobox_getItems(SongBox)
strings_add(items, "Pick a song..")
SongBox.ItemIndex = 0

songTable = {
{songName = "Adele - Hello", songPath = "E:\\Lagu Film Dll\\Filmograph\\Lagu MP3\\Barat\\Adele - Hello.mp3"},
{songName = "Billy Joel - An Innocent Man", songPath = "E:\\Lagu Film Dll\\Filmograph\\Lagu MP3\\Barat\\Billy Joel - An Innocent Man.mp3"},
{songName = "Celine Dion - My Heart Will Go On", songPath = "E:\\Lagu Film Dll\\Filmograph\\Lagu MP3\\Barat\\Celine Dion - My Heart Will Go On.mp3"},
{songName = "Chris Brown - Dont Wake Up", songPath = "E:\\Lagu Film Dll\\Filmograph\\Lagu MP3\\Barat\\Chris Brown - Dont Wake Up.mp3"},
{songName = 'Kate Bush - Wuthering Height', songPath = "E:\\Lagu Film Dll\\Filmograph\\Lagu MP3\\Barat\\Kate Bush - Wuthering Height.mp3"}
}

for i,v in ipairs(songTable) do
 strings_add(items, v.songName)
end

function cbboxOnChange()
 index = getProperty(SongBox, "ItemIndex")
 index = songTable[index]
 if index == nil then
 MsLabel.Caption = 'Idle..'
 else
 local ss = createMemoryStream()
 path = index.songPath
 ss.loadFromFile(path)
 playSound(ss)
 ss.Destroy()
 MsLabel.Caption = "Playing - "..index.songName
 end
end
SongBox.onChange = cbboxOnChange

bStop = createButton(Mform)
bStop.Left = 10
bStop.Top = MsLabel.Top + MsLabel.Height + 20
bStop.Height = 25
bStop.Width = 70
bStop.Caption = 'Stop'
bStop.Cursor = -21
bStop.Name = 'bStop'

bExplo = createButton(Mform)
bExplo.Left = bStop.Left + bStop.Width + 25
bExplo.Top = MsLabel.Top + MsLabel.Height + 20
bExplo.Height = 25
bExplo.Width = 70
bExplo.Caption = 'Find MP3'
bExplo.Cursor = -21
bExplo.Name = 'bExplo'

bExit = createButton(Mform)
bExit.Width = 70
bExit.Left = Mform.Width - bExit.Width - 10
bExit.Top = MsLabel.Top + MsLabel.Height + 20
bExit.Height = 25
bExit.Caption = 'Exit'
bExit.Cursor = -21
bExit.Name = 'bExit'

function songStop()
 local check = MsLabel.Caption
 if check == 'Idle..' then
 showMessage("No song playing...")
 end
 playSound('silence.mp3')
 MsLabel.Caption = "Idle.."
 SongBox.ItemIndex = 0
 SongBox.Text = 'Pick a song..'
end

function GetFileName(f)
 local str = f
 local temp = ""
 local result = ""
 for i = str:len(), 1, -1 do
 if str:sub(i,i) ~= "/"  then
 temp = temp..str:sub(i,i)
 else
 break
 end
 end
 for j = temp:len(), 1, -1 do
 result = result..temp:sub(j,j)
 end
 return result
end

function exploMP3()
 load_dialog = createOpenDialog(self)
 load_dialog.InitalDir = os.getenv('%USERPROFILE%')
 load_dialog.execute()
 file = load_dialog.FileName
 a = GetFileName(file)
 if a == nil then
 return a
 else
 MsLabel.Caption = a
 local ss = createMemoryStream()
 ss.loadFromFile(file)
 playSound(ss)
 ss.destroy()
 end
end

function exit()
 closeCE()
 return caFree
end

bExit.onClick = exit
bStop.onClick = songStop
bExplo.onClick = exploMP3
Mform.Show()


plsound.lua -- add to table file

Code:
--- 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


You can change plSound.lua with mciSendstring module.
Beside, I am not really understand what exactly you want to do.

_________________
Stealing Code From Stolen Code...
And Admit It.. Hmmm....Typically LOL
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sun May 17, 2020 8:07 am    Post subject: Reply with quote

Note; I will try the samples you provided, thanks.
What I am trying to say (Project);

Code:
function CEButton1_Click(sender) --Background music
playMP3(path1)
end

function CEButton2_Click(sender) --The lady who sings the song
playMP3(path2)
end

function CEButton3_Click(sender) --The man who sings the song
playMP3(path3)
end

function CEButton4_Click(sender) --optional, add or remove (Stop) a wind.
if playMP3(path4) then
stopMP3(path4)
else
playMP3(path4)
end
end



When more than one button is active at the same time, it should play the songs.
He should play with him, without closing the current playing song.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Corroder
Grandmaster Cheater Supreme
Reputation: 75

Joined: 10 Apr 2015
Posts: 1668

PostPosted: Sun May 17, 2020 8:35 am    Post subject: Reply with quote

Aylin wrote:
Note; I will try the samples you provided, thanks.
What I am trying to say (Project);

When more than one button is active at the same time, it should play the songs.
He should play with him, without closing the current playing song.


Try the script I provided before:

Code:
function playMulti(song1, song2,...)
 if not initializeMP3Player() then return end
 local fileName
 fileName = song1
 MP3PlayerSendCommand("open "..fileName.." type mpegvideo alias FirstSound", 0, 0, 0)
 MP3PlayerSendCommand("play FirstSound", 0, 0, 0)

 fileName = song2
 MP3PlayerSendCommand("open "..fileName.." type mpegvideo alias SecondSound", 0, 0, 0)
 MP3PlayerSendCommand("play SecondSound",0, 0, 0)
end

----- Test, change song files with your own
s1 = "E:\\test1.mp3"
s2 = "E:\\test2.mp3"
playMulti(s1,s2)

_________________
Stealing Code From Stolen Code...
And Admit It.. Hmmm....Typically LOL
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sun May 17, 2020 1:32 pm    Post subject: Reply with quote

And the final;
Run multiple mp3 files simultaneously;

Code:
function MP3PlayerSendCommand(command)
  writeStringLocal(MP3PlayerCommandMS.Memory, command, true)
  writeBytesLocal (MP3PlayerCommandMS.Memory+2*#command, 0, 0)
  executeCodeLocal('SimpleMp3Player',MP3PlayerCommandMS.Memory)
  return readStringLocal(MP3PlayerCommandMS.Memory+1024,512,true),
         readStringLocal(MP3PlayerCommandMS.Memory+768,128,true)
end

function playMP3(path)
  if not initializeMP3Player() then return end

  MP3PlayerSendCommand('resume MediaFile')--('close MediaFile')
  MP3PlayerSendCommand( string.format('open "%s" type mpegvideo alias MediaFile',path) )
  MP3PlayerSendCommand('play MediaFile')
end
---------------------------------------------------

function MP3PlayerSendCommand1(command)
  writeStringLocal(MP3PlayerCommandMS.Memory, command, true)
  writeBytesLocal (MP3PlayerCommandMS.Memory+2*#command, 0, 0)
  executeCodeLocal('SimpleMp3Player',MP3PlayerCommandMS.Memory)
  return readStringLocal(MP3PlayerCommandMS.Memory+1024,512,true),
         readStringLocal(MP3PlayerCommandMS.Memory+768,128,true)
end

function playMP31(path1)
  if not initializeMP3Player() then return end

  MP3PlayerSendCommand1('resume MediaFile1')--('close MediaFile1')
  MP3PlayerSendCommand1( string.format('open "%s" type mpegvideo alias MediaFile1',path1) )
  MP3PlayerSendCommand1('play MediaFile1')
end

function stopMP3()
  if not initializeMP3Player() then return end

  MP3PlayerSendCommand('close MediaFile')
  MP3PlayerSendCommand1('close MediaFile1')
end


Thanks @Corroder

Now it is left to add "findTableFile" to this code.
There are 17 audio files. I will duplicate this code up to 17. Wink

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Corroder
Grandmaster Cheater Supreme
Reputation: 75

Joined: 10 Apr 2015
Posts: 1668

PostPosted: Sun May 17, 2020 1:38 pm    Post subject: Reply with quote

Yes, don't close media when start playing others media

See here:
https://www.youtube.com/watch?v=ZSO-bOwumcE&feature=youtu.be

_________________
Stealing Code From Stolen Code...
And Admit It.. Hmmm....Typically LOL
Back to top
View user's profile Send private message
AylinCE
Grandmaster Cheater Supreme
Reputation: 34

Joined: 16 Feb 2017
Posts: 1432

PostPosted: Sun May 17, 2020 2:04 pm    Post subject: Reply with quote

Corroder wrote:
Yes, don't close media when start playing others media

See here:
https://www.youtube.com/watch?v=ZSO-bOwumcE&feature=youtu.be
Cool Cool Cool

This is what I was trying to say.
Thanks for developing.
50% of my project was this code.
Now I need to get an idea for the remaining code. I have to open a forum question.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Xenocritus
Cheater
Reputation: 0

Joined: 27 Dec 2020
Posts: 25

PostPosted: Fri Jan 29, 2021 8:55 am    Post subject: Reply with quote

Hi,

Im using MP3 player to replace some game's music and it works. However I have an issue.

Working Workflow:
- Start CE
- initializeMP3Player()
- Attach the game
- Run the program logic to replace
- It works

Not Working (seems like in a loop once Lua executed)
- Start CE
- Attach the game
- initializeMP3Player()
- Just the CE not responding

Is somehow the memory allocation entering in clonflict? I just want to attach the game and run all the Lua Scripts.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials -> LUA Tutorials All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites