找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5350|回复: 0
打印 上一主题 下一主题
收起左侧

为madplay编写应用程序

[复制链接]
跳转到指定楼层
楼主
ID:72519 发表于 2015-1-20 02:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

这篇文章的app程序是参考国嵌的。

在编写app之前我们要编译好madplay


准备工作一:

编译madplay

首先解压三个压缩文件

[root@localhost ~]# cd /work/projects/sound/

[root@localhost sound]# ls

libid3tag-0.15.1b.tar.gz libmad-0.15.1b.tar.gz madplay-0.15.2b.tar.gz

[root@localhost sound]# tar xzf libid3tag-0.15.1b.tar.gz  //从名字上看是个库

[root@localhost sound]# tar xzf libmad-0.15.1b.tar.gz     //这个也是库

[root@localhost sound]# tar xzf madplay-0.15.2b.tar.gz  //这个是应用程序,它依赖这两个库

[root@localhost sound]#


[root@localhost sound]# cd libid3tag-0.15.1b

[root@localhost libid3tag-0.15.1b]# ./configure--host=arm-linux --prefix=/work/projects/sound/tmp

configure: WARNING: If you wanted to set the --build type, don't use--host.

    If a cross compiler isdetected then cross compile mode will be used.

checking for a BSD-compatible install... /usr/bin/install -c

checking whether build environment is sane... yes


然后再

make

make install
再按照上面的方法进入libmad-0.15.1b文件夹编译

./configure --host=arm-linux --prefix=/work/projects/sound/tmpLDFLAGS="-L/work/projects/sound/tmp/lib" CFLAGS="-I/work/projects/sound/tmp/include"

注意: -L/work…..

这个-L与/之间没有空格.

然后再

make

make install

把tmp/bin/*  tmp/lib/*so* -d把库文件复制到开发板lib文件夹,bin文件复制到开发板的bin文件夹


# madplay --tty-control /mnt/mp3/beyond.mp3

MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 RobertLeslie et al.

s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66

         Artist: Beyond£¨»Æ¼ò¾Ô£©

          Album:òôàÖμîìÃMusicPalace

        Comment:http://music.zkinfo.ha.cn

s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66


到这里时候测试下自己的开发板能否播放mp3音乐。

注意事项:确保自己的开发板已经有声卡了,想提高播放音乐的音量不能用madplay提供的方法(声音加大会破掉,而且音质会变得很差),如果你的开发板有QT界面直接调整音量滑块。


准备工作二:

编写开发板上的驱动程序。我的开发板是TQ2440。

key_drv_irq.c

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <linux/irq.h>
  7. #include <asm/uaccess.h>
  8. #include <asm/irq.h>
  9. #include <asm/io.h>
  10. #include <asm/arch/regs-gpio.h>
  11. #include <asm/hardware.h>

  12. static int major;
  13. static struct class *key_class;
  14. static struct class_device        *key_class_dev;

  15. volatile unsigned long *gpfcon;
  16. volatile unsigned long *gpfdat;

  17. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  18. /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
  19. static volatile int ev_press = 0;


  20. struct pin_desc{
  21.         unsigned int pin;
  22.         unsigned int key_val;
  23. };


  24. /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
  25. /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
  26. static unsigned char key_val;

  27. struct pin_desc pins_desc[4] = {
  28.         {S3C2410_GPF1, 0x01},
  29.         {S3C2410_GPF4, 0x02},
  30.         {S3C2410_GPF2, 0x03},
  31.         {S3C2410_GPF0, 0x04},
  32. };

  33. /*
  34.   * 确定按键值
  35.   */
  36. static irqreturn_t buttons_irq(int irq, void *dev_id)
  37. {
  38.         struct pin_desc * pindesc = (struct pin_desc *)dev_id;
  39.         unsigned int pinval;
  40.        
  41.         pinval = s3c2410_gpio_getpin(pindesc->pin);

  42.         if (pinval)
  43.         {
  44.                 /* 松开 */
  45.                 key_val = 0x80 | pindesc->key_val;
  46.         }
  47.         else
  48.         {
  49.                 /* 按下 */
  50.                 key_val = pindesc->key_val;
  51.         }

  52.   ev_press = 1;                  /* 表示中断发生了 */
  53.   wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
  54.        
  55.         return IRQ_RETVAL(IRQ_HANDLED);
  56. }

  57. static int key_drv_open(struct inode *inode, struct file *file)
  58. {
  59.   /* 配置成输入模式 */
  60.   request_irq(IRQ_EINT1, buttons_irq, IRQT_BOTHEDGE, "K1", &pins_desc[0]);
  61.   request_irq(IRQ_EINT4, buttons_irq, IRQT_BOTHEDGE, "K2", &pins_desc[1]);  
  62.   request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "K3", &pins_desc[2]);
  63.   request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "K4", &pins_desc[3]);
  64.    
  65.   return 0;
  66. }

  67. static ssize_t key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
  68. {
  69.         if (size != 1)
  70.                 return -EINVAL;

  71.         /* 如果没有按键动作, 休眠 */
  72.         wait_event_interruptible(button_waitq, ev_press);

  73.         /* 如果有按键动作, 返回键值 */
  74.         copy_to_user(buf, &key_val, 1);
  75.         ev_press = 0;
  76.        
  77.         return 1;
  78. }

  79. int key_dev_close(struct inode *inode, struct file *file)
  80. {
  81.         free_irq(IRQ_EINT1, &pins_desc[0]);
  82.         free_irq(IRQ_EINT4, &pins_desc[1]);
  83.         free_irq(IRQ_EINT2, &pins_desc[2]);
  84.         free_irq(IRQ_EINT0, &pins_desc[3]);
  85.   return 0;
  86. }
  87.             
  88. static struct file_operations key_drv_fops={
  89.   .owner=THIS_MODULE,
  90.   .open=key_drv_open,
  91.   .read=key_drv_read,
  92.   .release=key_dev_close,
  93. };

  94. static int key_drv_init(void)
  95. {
  96.   major=register_chrdev(0, "key_drv", &key_drv_fops);
  97.   key_class=class_create(THIS_MODULE, "keydrv");
  98.   key_class_dev=class_device_create(key_class, NULL, MKDEV(major,0), NULL,"buttons"); /* dev/buttons */
  99.   
  100.   gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); //0x56000010是的GPIOB的
  101.         gpfdat = gpfcon + 1;
  102.        
  103.   return 0;
  104. }

  105. static void key_drv_exit(void)
  106. {
  107.   unregister_chrdev(major, "key_drv");
  108.   class_device_unregister(key_class_dev);
  109.   class_destroy(key_class);   //class_destory(key_class);
  110.   iounmap(gpfcon);
  111. }

  112. module_init(key_drv_init);
  113. module_exit(key_drv_exit);

  114. MODULE_LICENSE("GPL");
复制代码

准备工作三:

app-mp3.c

  1. /*
  2. *     mp3播放器控制程序
  3. *           功能:
  4.                          k1:播放、暂停
  5.                          k2:停止播放
  6.                          k3:上一首
  7.                          k4:下一首
  8. *     附加:歌曲自动循环播放
  9. *
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <signal.h>
  19. #include <sys/select.h>
  20. #include <sys/time.h>
  21. #include <errno.h>
  22. #include <sys/wait.h>
  23. #include <string.h>
  24. #include <sys/ipc.h>
  25. #include <sys/shm.h>

  26. /*共享内存申请标记*/
  27. #define PERM S_IRUSR|S_IWUSR                                                                                                       

  28. /*双向循环列表:存放歌曲名*/
  29. struct song                               
  30. {
  31.         char songname[20];
  32.         struct song *prev;
  33.         struct song *next;
  34. };

  35. /*孙子进程id号*/
  36. pid_t gradchild;

  37. /*子进程id号*/
  38. pid_t pid;

  39. /*共享内存描述标记*/
  40. int shmid;

  41. char *p_addr;

  42. /*播放标记*/
  43. int first_key=1;
  44. int play_flag=0;

  45. /*************************************************
  46. Function name: play
  47. Parameter    : struct song *
  48. Description         : 播放函数
  49. Return                 : void
  50. Argument     : void
  51. Autor & date : ada 09,12,07
  52. **************************************************/
  53. void play(struct song *currentsong)
  54. {
  55.         pid_t fd;
  56.         char *c_addr;
  57.         char *p;
  58.         int len;
  59.         char my_song[30]="/mp3/";
  60.         while(currentsong)
  61.         {
  62.                 /*创建子进程,即孙子进程*/
  63.                 fd = fork();
  64.                 if(fd == -1)
  65.                 {       
  66.                         perror("fork");
  67.                         exit(1);
  68.                 }
  69.                 else if(fd == 0)
  70.                 {
  71.                         /*把歌曲名加上根路径*/
  72.                         strcat(my_song,currentsong->songname);
  73.                         p = my_song;
  74.                         len = strlen(p);

  75.                         /*去掉文件名最后的'\n'*/
  76.                         my_song[len-1]='\0';

  77.                         printf("THIS SONG IS %s\n",my_song);
  78.                         execl("/bin/madplay","madplay",my_song,NULL);
  79.                         printf("\n\n\n");
  80.                 }
  81.                 else
  82.                 {
  83.                         /*内存映射*/
  84.                         c_addr = shmat(shmid,0,0);

  85.                         /*把孙子进程的id和当前播放歌曲的节点指针传入共享内存*/
  86.                         memcpy(c_addr,&fd,sizeof(pid_t));
  87.                         memcpy(c_addr + sizeof(pid_t)+1,¤tsong,4);
  88.                         /*使用wait阻塞孙子进程,直到孙子进程播放完才能被唤醒;
  89.                           当被唤醒时,表示播放MP3期间没有按键按下,则继续顺序播放下一首MP3*/
  90.                         if(fd == wait(NULL))
  91.                         {
  92.                                 currentsong = currentsong->next;
  93.                                 printf("THE NEXT SONG IS %s\n",currentsong->songname);
  94.                         }
  95.                 }
  96.         }
  97. }

  98. /*************************************************
  99. Function name: creat_song_list
  100. Parameter    : void
  101. Description         : 创建歌曲名的双向循环链表
  102. Return                 : struct song *
  103. Argument     : void
  104. Autor & date : ada 09.12.07
  105. **************************************************/
  106. struct song *creat_song_list(void)
  107. {       
  108.         FILE *fd;
  109.         size_t size;
  110.         size_t len;
  111.         char *line = NULL;
  112.         struct song *head;
  113.         struct song *p1;
  114.         struct song *p2;
  115.         system("ls /mp3 >song_list");
  116.         fd = fopen("song_list","r");

  117.         p1 = (struct song *)malloc(sizeof(struct song));

  118.         printf("==================================song list=====================================\n");
  119.         system("ls /mp3");       
  120.         printf("\n");
  121.         printf("================================================================================\n");
  122.         size = getline(&line,&len,fd);

  123.         strncpy(p1->songname,line,strlen(line));
  124.         head = p1;
  125.         while((size = getline(&line,&len,fd)) != -1)
  126.         {       
  127.                 p2 = p1;
  128.                 p1 = (struct song *)malloc(sizeof(struct song));
  129.                 strncpy(p1->songname,line,strlen(line));
  130.                 p2->next = p1;
  131.                 p1->prev = p2;       
  132.         }
  133.         p1->next = head;
  134.         head->prev = p1;
  135.         p1 = NULL;
  136.         p2 = NULL;
  137.         system("rm -rf song_list");
  138.         return head;
  139. }
  140. /*************************************************
  141. Function name: startplay
  142. Parameter    : pid_t *,struct song *
  143. Description         : 开始播放函数
  144. Return                 : void
  145. Argument     : void
  146. Autor & date : ada 09.12.07
  147. **************************************************/
  148. void startplay(pid_t *childpid,struct song *my_song)
  149. {
  150.         pid_t pid;
  151.         int ret;
  152.         /*创建子进程*/
  153.         pid = fork();

  154.         if(pid > 0)
  155.         {
  156.                 *childpid = pid;
  157.                 play_flag = 1;
  158.                 sleep(1);
  159.                 /*把孙子进程的pid传给父进程*/
  160.                 memcpy(&gradchild,p_addr,sizeof(pid_t));
  161.         }
  162.         else if(0 == pid)
  163.         {       
  164.                 /*子进程播放MP3函数*/
  165.                 play(my_song);
  166.         }
  167. }
  168. /*************************************************
  169. Function name: my_pause
  170. Parameter    : pid_t
  171. Description         : 暂停函数
  172. Return                 : void
  173. Argument     : void
  174. Autor & date : ada 09,12,07
  175. **************************************************/
  176. void my_pause(pid_t pid)
  177. {
  178.         printf("=======================PAUSE!PRESS K1 TO CONTINUE===================\n");
  179.         kill(pid,SIGSTOP); //对孙子进程发送SKGSTOP信号
  180.         play_flag = 0;
  181. }

  182. /*************************************************
  183. Function name: my_pause
  184. Parameter    : pid_t
  185. Description         : 停止播放函数
  186. Return                 : void
  187. Argument     : void
  188. Autor & date : ada 09,12,07
  189. **************************************************/
  190. void my_stop(pid_t g_pid)
  191. {

  192.         printf("=======================STOP!PRESS K1 TO START PLAY===================\n");
  193.         kill(g_pid,SIGKILL); //对孙子进程发送SKGKILL信号
  194.         kill(pid,SIGKILL);   //对子进程发送SKGKILL信号
  195.         first_key=1;

  196. }

  197. /*************************************************
  198. Function name: conti_play
  199. Parameter    : pid_t
  200. Description         : 继续函数
  201. Return                 : void
  202. Argument     : void
  203. Autor & date : ada 09,12,07
  204. **************************************************/
  205. void conti_play(pid_t pid)
  206. {
  207.         printf("===============================CONTINUE=============================\n");
  208.         kill(pid,SIGCONT); //对孙子进程发送SIGCONT信号
  209.         play_flag=1;
  210. }

  211. /*************************************************
  212. Function name: next
  213. Parameter    : pid_t
  214. Description         : 下一首函数
  215. Return                 : void
  216. Argument     : void
  217. Autor & date : ada 09.12.07
  218. **************************************************/
  219. void next(pid_t next_pid)
  220. {
  221.         struct song *nextsong;

  222.         printf("===============================NEXT MP3=============================\n");
  223.         /*从共享内存获得孙子进程播放歌曲的节点指针*/
  224.         memcpy(&nextsong,p_addr + sizeof(pid_t)+1,4);
  225.         /*指向下首歌曲的节点*/
  226.         nextsong = nextsong->next;
  227.         /*杀死当前歌曲播放的子进程,孙子进程*/
  228.         kill(pid,SIGKILL);
  229.         kill(next_pid,SIGKILL);
  230.         wait(NULL);
  231.         startplay(&pid,nextsong);
  232. }

  233. /*************************************************
  234. Function name: prev
  235. Parameter    : pid_t
  236. Description         : 上一首函数
  237. Return                 : void
  238. Argument     : void
  239. Autor & date : yuanhui 09.12.08
  240. **************************************************/
  241. void prev(pid_t prev_pid)
  242. {
  243.         struct song *prevsong;
  244.         /*从共享内存获得孙子进程播放歌曲的节点指针*/
  245.         printf("===============================PRIOR MP3=============================\n");
  246.         memcpy(&prevsong,p_addr + sizeof(pid_t)+1,4);
  247.         /*指向上首歌曲的节点*/
  248.         prevsong = prevsong->prev;
  249.         /*杀死当前歌曲播放的子进程,孙子进程*/
  250.         kill(pid,SIGKILL);
  251.         kill(prev_pid,SIGKILL);
  252.         wait(NULL);
  253. //linux C中的wait(NULL)是什么意思?请问_百度知道
  254. //答:等待子进程退出。NULL的意思是退出状态不关注。如果要获取退出状态应该写成wait(&status);
  255.         startplay(&pid,prevsong);
  256. }

  257. /*************************************************
  258. Function name: main
  259. Parameter    : void
  260. Description         : 主函数
  261. Return                 : int
  262. Argument     : void
  263. Autor & date : ada 09.12.07
  264. **************************************************/
  265. int main(void)
  266. {
  267.         int buttons_fd;
  268.         int key_value;
  269.         struct song *head;
  270.         /*打开设备文件*/
  271.         buttons_fd = open("/dev/buttons", O_RDWR);
  272.         if (buttons_fd < 0) {
  273.                 perror("open /dev/buttons fail!!!");
  274.                 exit(1);
  275.         }


  276.   /*创建播放列表*/
  277.         head = creat_song_list();
  278.         printf("===================================OPTION=======================================\n\n\n\n");
  279.         printf("        K1:START/PAUSE     K2:STOP   K3:NEXT      K4:PRIOR\n\n\n\n");
  280.         printf("================================================================================\n");


  281.   /*共享内存:用于存放子进程ID,播放列表位置*/
  282.         if((shmid = shmget(IPC_PRIVATE,5,PERM))== -1)
  283.                 exit(1);
  284.         p_addr = shmat(shmid,0,0);
  285.         memset(p_addr,'\0',1024);
  286.        
  287.        
  288.         while(1)
  289.         {
  290.                         unsigned char key_value;
  291.                        
  292.                         read(buttons_fd, &key_value, 1);       
  293.                         key_value--;
  294.       /*首次播放,必须是按键1*/
  295.       if(first_key) {
  296.         switch(key_value)
  297.         {       
  298.           case 0:
  299.               startplay(&pid,head);
  300.               first_key=0;
  301.             break;
  302.           case 1:
  303.           case 2:
  304.           case 3:
  305.             printf("=======================PRESS K1 TO START PLAY===================\n");
  306.           break;
  307.          default:
  308.             printf("=======================PRESS K1 TO START PLAY===================\n");
  309.           break;
  310.         } //end switch
  311.       }//end if(first_key)
  312.       /*若不是首次播放,则根据不同键值处理*/
  313.       else if(!first_key) {
  314.         switch(key_value)
  315.         {
  316.           case 0:
  317.           //printf("play_flag:%d\n",play_flag);
  318.           if(play_flag)
  319.           my_pause(gradchild);
  320.           else
  321.           conti_play(gradchild);
  322.           break;
  323.           case 1:
  324.           my_stop(gradchild);
  325.           break;
  326.           case 2:
  327.           next(gradchild);
  328.           break;
  329.           case 3:
  330.           prev(gradchild);
  331.           break;
  332.         } //end switch
  333.       }//end if(!first_key)
  334.         }

  335.         close(buttons_fd);
  336.         return 0;
  337. }
复制代码

准备工作四:

在开发板根目录建立mp3文件夹,拷贝几首MP3文件进去,注意文件名不要超过20个字符。



现在可以运行这个app-mp3应用程序了。

=======================PRESS K1 TO START PLAY===================
=======================PRESS K1 TO START PLAY===================
=======================PRESS K1 TO START PLAY===================
THIS SONG IS /mp3/Tank.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
          Title: 贩贩贩        Artist: Tank(贩s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
===============================NEXT MP3=============================
THIS SONG IS /mp3/beyond.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
         Artist: Beyond(黄家驹)
          Album: 音乐殿堂Musics3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Palace
        Comment: http://music.zkinfo.ha.cn
error: frame 12346: lost synchronization
12346 frames decoded (0:05:22.5), +0.6 dB peak amplitude, 19 clipped samples
THE NEXT SONG IS huanghun.mp3


THIS SONG IS /mp3/huanghun.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
          Title: 黄昏
         Artist: 周传雄 (小刚)
          s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Album: transfer
           Year: 2000
          Genre: Pop
        Comment: mp3.attin.com




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表