Controlling MP3 playback: a Model-View-Controller approach

Discussion about writing software for VS1005 and the VSOS Operating System. Also posts about VS1005-related hardware design and device drivers should be posted here.
Post Reply
User avatar
Panu
VLSI Staff
Posts: 2405
Joined: Tue 2010-06-22 13:43

Controlling MP3 playback: a Model-View-Controller approach

Post by Panu » Fri 2014-07-18 13:28

Dear Forum Members,

VSOS employs a Model-View-Controller approach to MP3 (and other audio formats) playing. This means that there are essentially 3 parts to do with music playing.

1. The MP3MODEL (MP3MODEL.DL3) is the functionality of a music player. It is a library and a task in memory, which listens to messages. When asked to do so, it opens a music file, finds the correct decoder, and plays the audio via the stdaudioout interface of VSOS3. It expects to have a VIEW component associated to it, and to the VIEW Component it sends messages such as album name, artist, title, play time elapsed etc messages and expects the VIEW to show these to the user.

2. The MP3VIEW component receives UImessages from the MP3MODEL. It shows information about the current playback status to the user and usually makes some of that information available to other pieces of software that are running in the system.

3. The CONTROLLER component is any piece of software in the system which can send UImessages to the MODEL. These UImessages can command the MP3MODEL to play a file from some VSOS disk or device, to pause, stop, select a playlist, move to the next song etc.

There's also a SYSTEM wide UImessage receiver, that can receive global messages such as SET_VOLUME or SET_BALANCE.

Here are some example files for the MODEL-VIEW-CONTROLLER, and I hope I will soon be able to make an educational video to demonstrate their usage.


File 1: arch-VSOS311-2014-07-15-23-03-1.zip

First of all, you need to compile this kernel version. It is because I forgot to export the "AddSymbol" kernel interface in the 2.19 release of VSIDE. Compiling this kernel will add the interface to libvs1005g_vsos3/vsoso03.0 so the code will compile.

File 2: arch-MP3MODEL-2014-07-15-23-13-2.zip

There have been many releases of the MP3MODEL.DL3 in the past few days. For this demo (controlling the playback from separate DL3 libraries), a version of the MP3MODEL is needed, which sets a system-wide function pointer modelCallbacks[0] to point to itself. This way other DL3 libraries can easily find the model.

Code: Select all

void init() {
	modelCallbacks[0]=ModelCallback; // publish our model callback
	InitMutexN(&mutex,1);
	StartTask(TASK_DECODER,ModelTask); // in mp3model.c
	Yield(); // Release the CPU to allow the MP3 decoder task to initialize
}
Code above: The MP3MODEL publises its callback function in modelCallbacks[0] and starts a new task in which the MP3 decoding/playing runs.


File 3: arch-MP3VIEW1-2014-07-15-23-03-1.zip

This is a MP3VIEW component, which uses printf to show the messages it receives from the model. It also publishes the playState information from the model, so that the MP3WAIT component knows whether the model is currently playing or not.

Code: Select all

void init(void) {
	// Publish our variable playState in the system namespace
	AddSymbol("_playState",NULL,(u_int16)&playState);
	mp3ModelCallback = modelCallbacks[0];
	SendMessageToModel(-1,UIMSG_VSOS_SET_CALLBACK_FUNCTION,(u_int32)ViewCallback);
}

Code: Select all

ioresult ViewCallback(s_int16 index,u_int16 message,u_int32 value) {
	if ((message & 0xFF00) == UIMSG_TEXT) {
		printf("MP3VIEW:%04x=\"%s\"\n",message,(char*)value);
	} else {
		printf("MP3VIEW:%04x=%ld. ", message,value);
	}
	if (message == UIMSG_S16_PLAYING) {
		playState = value;
	}
	return S_OK;
}
Code above: MP3VIEW registers as a listener of messages from the MP3MODEL and publishes a system-wide global variable playState for other components to read. The View callback shows messages on the console and updates the playState variable.


File 4: arch-MP3PLAY-2014-07-15-23-03-1.zip

This is a CONTROLLER component, which tells the MP3MODEL to play a file. The file name is given as a parameter in CONFIG.TXT.

Code: Select all

int main(char *parameters) {
	sendMsgToModel = modelCallbacks[0];
	// If we find the MP3 model then send a message to MP3 model to play the file 
	if (sendMsgToModel) {
		sendMsgToModel(-1,UIMSG_TEXT_OPEN_FILE,(u_int32)parameters);
		Delay(2000);
		return S_OK;
	}
	return S_ERROR; //MP3 model not found
}
Code above: The MP3PLAY controller finds the model from modelCallbacks[0] and sends a UImessage to the model, asking it to play a file.


File 5: arch-MP3WAIT-2014-07-15-23-03-1.zip

This library waits until the MP3MODEL is not playing a song any more. This is a very simple library, but it is the key of understanding the whole data flow from MP3MODEL to MP3VIEW to MP3WAIT.

Code: Select all

  DLLIMPORT (playState)
  extern u_int16 playState; //This is exported by MP3VIEW, load it first.

  int main(char *parameters) {
        while(playState) {
                printf("\nMP3WAIT: Current playstate is %d, waiting for playing to
stop.\n",playState);
                Delay(5000);
        }
        return S_OK;
  }
Code above: MP3WAIT imports the playState varible, published by the MP3VIEW and waits until the playing is stopped.

In my test, I have the following CONFIG.TXT:

Code: Select all

SDSD e
MP3MODEL
MP3VIEW1
MP3PLAY e:test.mp3
MP3WAIT
MP3PLAY e:test.mp3
MP3WAIT
MP3PLAY s:ding.wav
MP3WAIT
which produces the following output in the serial port:

Code: Select all

Hello.
VSOS 3.10 build Jun 14 2014 10:03:42
VLSI Solution Oy 2012-2014 - http://www.vlsi.fi

Starting the kernel.. Starting Devices...  External SPI Flash
Installed system devices:
S: SPI Flash c814, handled by FAT.
Load drivers...
Driver: SDSD... E: SD card in SD mode

Driver: MP3MODEL...
Driver: MP3VIEW1...
Driver: MP3PLAY... playState=12345
MP3VIEW:050b="e:test.mp3"
MP3VIEW:0503="Angels Crying"
MP3VIEW:0505="E-Type"
MP3VIEW:0504="Last Man Standing"
MP3VIEW:0506="1998"
MP3VIEW:030a=0. MP3VIEW:030b=0. MP3VIEW:0204=2. MP3VIEW:030a=1.
MP3VIEW:030b=3. MP3VIEW:030a=2. MP3VIEW:030b=6.
Driver: MP3WAIT...
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=3. MP3VIEW:030b=10. MP3VIEW:030a=4. MP3VIEW:030b=13.
MP3VIEW:030a=5. MP3VIEW:030b=16. MP3VIEW:030a=6. MP3VIEW:030b=20.
MP3VIEW:030a=7. MP3VIEW:030b=23.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=8. MP3VIEW:030b=26. MP3VIEW:030a=9. MP3VIEW:030b=30.
MP3VIEW:030a=10. MP3VIEW:030b=33. MP3VIEW:030a=11. MP3VIEW:030b=36.
MP3VIEW:030a=12. MP3VIEW:030b=40.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=13. MP3VIEW:030b=43. MP3VIEW:030a=14. MP3VIEW:030b=46.
MP3VIEW:030a=15. MP3VIEW:030b=50. MP3VIEW:030a=16. MP3VIEW:030b=53.
MP3VIEW:030a=17. MP3VIEW:030b=56.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=18. MP3VIEW:030b=60. MP3VIEW:030a=19. MP3VIEW:030b=63.
MP3VIEW:030a=20. MP3VIEW:030b=66. MP3VIEW:030a=21. MP3VIEW:030b=70.
MP3VIEW:030a=22. MP3VIEW:030b=73.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=23. MP3VIEW:030b=76. MP3VIEW:030a=24. MP3VIEW:030b=80.
MP3VIEW:030a=25. MP3VIEW:030b=83. MP3VIEW:030a=26. MP3VIEW:030b=86.
MP3VIEW:030a=27. MP3VIEW:030b=90.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=28. MP3VIEW:030b=93. MP3VIEW:030a=29. MP3VIEW:030b=96.
MP3VIEW:030a=30. MP3VIEW:030b=100. MP3VIEW:0204=0.
Driver: MP3PLAY... playState=0
MP3VIEW:050b="e:test.mp3"
MP3VIEW:0503="Angels Crying"
MP3VIEW:0505="E-Type"
MP3VIEW:0504="Last Man Standing"
MP3VIEW:0506="1998"
MP3VIEW:030a=0. MP3VIEW:030b=0. MP3VIEW:0204=2. MP3VIEW:030a=1.
MP3VIEW:030b=3. MP3VIEW:030a=2. MP3VIEW:030b=6.
Driver: MP3WAIT...
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=3. MP3VIEW:030b=10. MP3VIEW:030a=4. MP3VIEW:030b=13.
MP3VIEW:030a=5. MP3VIEW:030b=16. MP3VIEW:030a=6. MP3VIEW:030b=20.
MP3VIEW:030a=7. MP3VIEW:030b=23.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=8. MP3VIEW:030b=26. MP3VIEW:030a=9. MP3VIEW:030b=30.
MP3VIEW:030a=10. MP3VIEW:030b=33. MP3VIEW:030a=11. MP3VIEW:030b=36.
MP3VIEW:030a=12. MP3VIEW:030b=40.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=13. MP3VIEW:030b=43. MP3VIEW:030a=14. MP3VIEW:030b=46.
MP3VIEW:030a=15. MP3VIEW:030b=50. MP3VIEW:030a=16. MP3VIEW:030b=53.
MP3VIEW:030a=17. MP3VIEW:030b=56.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=18. MP3VIEW:030b=60. MP3VIEW:030a=19. MP3VIEW:030b=63.
MP3VIEW:030a=20. MP3VIEW:030b=66. MP3VIEW:030a=21. MP3VIEW:030b=70.
MP3VIEW:030a=22. MP3VIEW:030b=73.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=23. MP3VIEW:030b=76. MP3VIEW:030a=24. MP3VIEW:030b=80.
MP3VIEW:030a=25. MP3VIEW:030b=83. MP3VIEW:030a=26. MP3VIEW:030b=86.
MP3VIEW:030a=27. MP3VIEW:030b=90.
MP3WAIT: Current playstate is 2, waiting for playing to stop.
MP3VIEW:030a=28. MP3VIEW:030b=93. MP3VIEW:030a=29. MP3VIEW:030b=96.
MP3VIEW:030a=30. MP3VIEW:030b=100. MP3VIEW:0204=0.
Driver: MP3PLAY... playState=0
MP3VIEW:050b="s:ding.wav"
MP3VIEW:030a=0. MP3VIEW:030b=0. MP3VIEW:0204=2. MP3VIEW:0204=0.
Driver: MP3WAIT...

9 driver(s) loaded.

VSOS running with 5 tasks:
Task   I/O Stack:0010-020f (512w), free:216
Task   Int Stack:0210-024f ( 64w), free:22
Task   Net Stack:0250-0251 (  2w), free:1
Task    UI Stack:0252-0253 (  2w), free:1
Task DECOD Stack:0254-03cf (380w), free:157

INT0_DAC:2->37765 INT13_RX:1->32923 INT16_TI2:2->12809

Load S:INIT.AP3...Open Failed: S:INIT.AP3
S:INIT.AP3 not found.
Nothing to do.

In the headphones, I can hear TEST.MP3 playing two times from the SD card, and then DING.WAV from the flash.

-Panu

PS. I hope soon to have a video demonstration of this.
Attachments
arch-MP3WAIT-2014-07-15-23-03-1.zip
MP3WAIT library that waits until music playback has been stopped. Needs MP3VIEW1.
(8.75 KiB) Downloaded 131 times
arch-MP3PLAY-2014-07-15-23-03-1.zip
MP3PLAY controller for MP3MODEL
(9 KiB) Downloaded 130 times
arch-MP3VIEW1-2014-07-15-23-03-1.zip
MP3VIEW
(12.23 KiB) Downloaded 132 times
arch-MP3MODEL-2014-07-16-08-50-2.zip
MP3MODEL
(69.53 KiB) Downloaded 172 times
arch-VSOS311-2014-07-15-23-03-1.zip
VSOS kernel that publises the AddSymbol interface, needed by MP3VIEW
(182.36 KiB) Downloaded 128 times
Info: Line In and Line Out, VS1000 User interface, Overlay howto, Latest VSIDE, MCU Howto, Youtube
Panu-Kristian Poiksalo, VLSI Solution Oy

safans
Senior User
Posts: 84
Joined: Sat 2014-02-08 14:37

Re: Controlling MP3 playback: a Model-View-Controller approa

Post by safans » Wed 2014-07-30 5:23

Hi Panu,

Do you have a working example in a app ?
with list file, next, prev, stop, pause, play

Best regards,
Safans.

User avatar
Panu
VLSI Staff
Posts: 2405
Joined: Tue 2010-06-22 13:43

Re: Controlling MP3 playback: a Model-View-Controller approa

Post by Panu » Wed 2014-07-30 20:17

Hi!
Do you have a working example in a app ?
with list file, next, prev, stop, pause, play
Yes. Actually, we plan to update the player software on the boards within the next month or so with our current software whics supports unicode characters etc. But because it's not realeased yet, the situation is that apart from the examples already in VSIDE (most of it is for VSOS2 only), i'll need some time to come up with additional example code. Not long. The main idea is always the same: check which messages the MP3MODEL supports, and send those messages to the MP3MODEL.

-Panu
Info: Line In and Line Out, VS1000 User interface, Overlay howto, Latest VSIDE, MCU Howto, Youtube
Panu-Kristian Poiksalo, VLSI Solution Oy

nishikant
Senior User
Posts: 78
Joined: Mon 2014-12-08 15:39

Re: Controlling MP3 playback: a Model-View-Controller approa

Post by nishikant » Thu 2014-12-11 14:31

Hi Panu,
I am just curious to know that Do you have a working example in a app now ?
If so can you please share the details of the same.
Expecting a quick response from your end.

Post Reply

Who is online

Users browsing this forum: No registered users