Welcome to the second part of our Corona SDK music player tutorial. In this part we'll place the interface in stage, handle the app logic, button controls and the steps to build the final app.
Where We Left Off. . .
Please be sure to check part 1 of the series to fully understand this tutorial.
Step 1: Variables
These are the variables we'll use. Read the comments in the code to know more about them, some of their names are self explaining so there will be no comment there.
-- Variables local currentSong = 1 local playing local timerSource local min = 0 local sec = 0
Step 2: Functions
Declare all functions as local at the start.
-- Functions local Main = {} local buildGUI = {} local playCurrentSong = {} local stopSong = {} local nextSong = {} local prevSong = {} local updateInfo = {} local updateProgress = {}
Step 3: Main Function
Next we'll create the function that will initialize all the app logic:
-- Main Function function Main() buildGUI() end
Step 4: Build the GUI
The following function places all of the GUI on the stage. It is built in the same order that we declared the variables, so you will easily identify each part by the variable names.
function buildGUI() bg = display.newImage('background.png') infoBar = display.newImage('infoBar.png', 20, 168) imageMarker = display.newImage('imageMarker.png', 30, 178) cdCover = display.newImage('s1.png', 30, 178) titleText = display.newText('1. Here Without You', 117, 176, native.systemFontBold, 14) titleText:setTextColor(246, 237, 240) byText = display.newText('By', 121, 197, native.systemFont, 10) byText:setTextColor(191, 182, 183) artistText = display.newText('3 Doors Down', 137, 197, native.systemFontBold, 10) artistText:setTextColor(244, 204, 106) buttonBar = display.newImage('buttonBar.png', 20, 278) playBtn = display.newImage('playBtn.png', 25, 279) stopBtn = display.newImage('stopBtn.png', 27, 282) stopBtn.isVisible = false prevBtn = display.newImage('prevBtn.png', 55, 279) nextBtn = display.newImage('nextBtn.png', 85, 279) progressBar = display.newImage('progressBar.png', 126, 290) progress = display.newRoundedRect(0, 0, 100, 10, 3) progress:setFillColor(244, 204, 106) progress:setReferencePoint(display.TopLeftReferencePoint) progress.x = 126 progress.y = 290 progress.isVisible = false current = display.newText('00:00', 235, 288, native.systemFont, 9) current:setTextColor(246, 237, 240) total = display.newText('/00:00', 259, 288, native.systemFont, 9) total:setTextColor(191, 182, 183) playBtn:addEventListener('tap', playCurrentSong) stopBtn:addEventListener('tap', stopSong) nextBtn:addEventListener('tap', nextSong) prevBtn:addEventListener('tap', prevSong) end
We add the tap listeners of the buttons in the last lines and this will make the buttons perform the corresponding function when tapped.
Step 5: Play Current Song
This code runs when the play button is pressed.
It resets the song and time counters (in case it's not the first time the button is pressed) and plays the song specified by the currentSong
variable. After that, the playing
variable is set to true, this will play the next or previous song automatically when the next or back buttons are pressed.
function playCurrentSong:tap(e) audio.rewind(songs[currentSong]) sec = 0 min = 0 audio.play(songs[currentSong]) playing = true updateInfo() timerSource = timer.performWithDelay(1000, updateProgress, 0) playBtn.isVisible = false stopBtn.isVisible = true end
It also starts the timer to begin the song duration counter and hides the play button to reveal the stop button.
Step 6: Stop Song
When the stop button is pressed, the current song stops playing and the timer is cancelled. Buttons are returned to normal and playing
is set to false.
function stopSong:tap(e) audio.stop() timer.cancel(timerSource) playBtn.isVisible = true stopBtn.isVisible = false playing = false end
Step 7: Next Song
This function stops the current song and changes to the next in the Table, if the playing
variable is set to
true it will play it automatically. It also checks if the next song is the last one, if that is the case it goes back to the first in the line.
function nextSong:tap(e) audio.stop() currentSong = currentSong + 1 if(currentSong > #songs) then currentSong = 1 end if(playing) then audio.rewind(songs[currentSong]) sec = 0 min = 0 audio.play(songs[currentSong]) end updateInfo() end
Step 8: Previous Song
As you may imagine this function behaves in the same way as the previous one, just backwards.
function prevSong:tap(e) audio.stop() currentSong = currentSong - 1 if(currentSong < 1) then currentSong = #songs end if(playing) then audio.rewind(songs[currentSong]) sec = 0 min = 0 audio.play(songs[currentSong]) end updateInfo() end
Step 9: Update Information
This code (called in the past three functions) handles the information displayed in both bars.
It updates the album art, title, artist and times of the songs.
function updateInfo() titleText.text = tostring(currentSong) .. '. ' .. songsInfo[currentSong][2] titleText:setReferencePoint(display.TopLeftReferencePoint) titleText.x = 117 artistText.text = songsInfo[currentSong][3] artistText:setReferencePoint(display.TopLeftReferencePoint) artistText.x = 137 display.remove(cdCover) cdCover = nil local cdCover = display.newImage(songsInfo[currentSong][4], 30, 178) local totalMin = math.floor(audio.getDuration(songs[currentSong]) / 1000 / 60)-- local totalSec = math.floor(audio.getDuration(songs[currentSong]) / 1000 % 60)-- total.text = '/' .. totalMin .. ':' .. totalSec total:setReferencePoint(display.topLeftReferencePoint) total.x = 275 end
Step 10: Update Progress
Executed every second, this function updates the progress bar of the song based on the current position and the total duration of it.
Note that the methods used by the Corona API may return different results depending on the format of the audio files.
function updateProgress:timer(e) sec = sec + 1 if(sec == 60) then sec = 0 min = min + 1 end local secS = tostring(sec) if(#secS < 2) then sec = '0' .. sec end current.text = min .. ':' .. sec current:setReferencePoint(display.topLeftReferencePoint) current.x = 250 -- Progress Bar local position = min .. sec position = position * 1000 local duration = audio.getDuration(songs[currentSong]) local percent = (position / duration) print(position, duration, percent) progress.isVisible = true progress.xScale = percent end
Step 11: Call the Main Function
In order to initially start the app, the Main function needs to be called. With the above code in place, we’ll do that here:
Main()
Step 12: Loading Screen
The Default.png file is an image that will be displayed right when you start the application while the iOS loads the basic data to show the Main Screen. Add this image to your project source folder, it will be automatically added by the Corona compliler.
Step 13: Icon
Using the graphics you created before you can now create a nice and good looking icon. The icon size for the non-retina iPhone icon is 57x57px, but the retina version is 114x114px and the iTunes store requires a 512x512px version. I suggest creating the 512×512 version first and then scaling down for the other sizes.
It doesn’t need to have the rounded corners or the transparent glare, iTunes and the iPhone will do that for you.
Step 14: Testing in the Simulator
It's time to do the final test. Open the Corona Simulator, browse to your project folder, and then click open. If everything works as expected, you are ready for the final step!
Step 15: Build
In the Corona Simulator go to File > Build and select your target device. Fill the required data and click
build. Wait a few seconds and your app will be ready for device testing and/or submission for distribution!
Conclusion
Experiment with the final result and try to make your custom version of the app!
I hope you liked this tutorial series and find it helpful. Thank you for reading!
Comments