单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:5646|回复: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




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

Powered by 单片机教程网