自己的MP3 maplay+ucGUi+tslib+歌词同显+频谱
madplay的移植在前几篇文章有过了,但是在移植后对madplay进行控制很不方便,于是在找工作的几天,写一段程序用socket添加在madplay中作为和主程序的通讯接口
# if defined(USE_TTY) && !defined(_WIN32)if ((player->options & PLAYER_OPTION_TTYCONTROL) &&setup_tty() == -1)player->options &= ~PLAYER_OPTION_TTYCONTROL;socket_fd = setup_socket(); //sxbg
# endif
修改player.c添加socket客户端初始化程序
int readkey(int blocking)
{
# if !defined(_WIN32)unsigned char key;ssize_t count = 0;if (!blocking) {/* tty_fd should be a tty in noncanonical mode with VMIN = VTIME = 0 */count = read(tty_fd, &key, 1);if(count == 0){if(socket_fd > 0) count = recv(socket_fd, &key, 1, MSG_DONTWAIT);}if (count == -1 && errno != EINTR && errno != EAGAIN) {error("tty", ":read");return -1;}return (count == 1) ? key : 0;}else {struct termios tty, save_tty;if (tcgetattr(tty_fd, &tty) == -1) {error("tty", ":tcgetattr");return -1;}save_tty = tty;/* change terminal temporarily to get a blocking read() */tty.c_cc[VMIN] = 1;if (tcsetattr(tty_fd, TCSANOW, &tty) == -1) {error("tty", ":tcsetattr");return -1;}do{//count = read(tty_fd, &key, 1);if(count == 0){if(socket_fd > 0){recv(socket_fd, &key, 1, MSG_DONTWAIT);count = recv(socket_fd, &key, 1, 0);}}}while (count == -1 && errno == EINTR);if (count == -1)error("tty", ":read");if (tcsetattr(tty_fd, TCSANOW, &save_tty) == -1) {error("tty", ":tcsetattr");return -1;}if (count == -1)return -1;return (count == 1) ? key : 0;}
修改以上代码,通过socket两者之间通信
这样主进程就能控制madplay的播放,停止,音量等功能,修改部分代码完成当前播放时间和剩余时间的查询以便为进度条做准备,
int get_lrc_Info(FILE *fp, unsigned int second, LRC_INFO *lrc_info)
{char data;unsigned long file_len;unsigned long cur_ofs;unsigned long start_ofs;unsigned long end_ofs;unsigned long mark_ofs;unsigned int time_s;unsigned int status; fseek(fp, 0L, SEEK_END);file_len = ftell(fp);start_ofs = 0; end_ofs = file_len-1;_RE_SCAN:cur_ofs = (start_ofs>end_ofs)?(start_ofs>end_ofs):(end_ofs-start_ofs);if(cur_ofs>100){cur_ofs = (start_ofs + end_ofs)/2;}else{cur_ofs = start_ofs;}fseek(fp,cur_ofs,SEEK_SET);status = 0;mark_ofs = cur_ofs;while(cur_ofs=0x30)&&(data<=0x39)) // 0 ~ 9{time_s = (data-0x30)*10*60;status++;}break;case 2: time_s += (data-0x30)*60;status++;break;case 3:if(data!=':'){while(1);}status++;break;case 4:time_s += (data-0x30)*10;status++;break; case 5: time_s += (data-0x30); status++;break;case 6: if(data == ']'){if(time_s == second){lrc_info->time_s = time_s;lrc_info->offset = cur_ofs;status++;} else if(time_s > second){ end_ofs = cur_ofs;goto _RE_SCAN;}else{start_ofs = cur_ofs;goto _RE_SCAN;}}break;case 7:if(data == 0x0A){ lrc_info->length = cur_ofs - lrc_info->offset;if(lrc_info->length <= 2) {start_ofs = cur_ofs;goto _RE_SCAN;}status++;return 0;}break;default:break;}if(status==8){break;}}if(status!=8){end_ofs = mark_ofs;goto _RE_SCAN;}return -1;
}void get_play_info(PLY_INFO *plyinfo)
{char cmd_tmp;char msg[64];int i = 0, j = 0, n;cmd_tmp = 'i';if(server_fd > 0){recv(server_fd, msg, 64, MSG_DONTWAIT);n = send(server_fd, &cmd_tmp, 1, 0);n = recv(server_fd, msg, 64, 0);}elsereturn ;msg[n] = '\0';printf("msg:%s\n", msg);while(i < n-6){if(msg[i] == ':' && msg[i+3] == ':'&& msg[i+6] == ' ' && msg[i+10] == ':'){break;}i++;}if(i < n-6){plyinfo->time_s = (msg[i+2]-0x30)*60 + (msg[i+4]-0x30)*10 + (msg[i+5]-0x30);current_time = plyinfo->time_s;remain_time = (msg[i+12]-0x30)*60 + (msg[i+14]-0x30)*10 + (msg[i+15]-0x30);j = 0;while(msg[i+17+j] != '.'){plyinfo->name[j] = msg[i+17+j];j++;}plyinfo->name[j] = '\0';}}
void *lrc_thread(void *arg)
{FILE* fp;unsigned int second;unsigned int i;unsigned char data;unsigned char cmd[16];unsigned char str[64];for(;;){get_play_info(&ply_info);current_time = ply_info.time_s;sprintf(cmd, "%s.lrc", ply_info.name);//printf("cmd*********%s\n", cmd);fp = fopen(cmd,"rd");if(fp == NULL){perror("Lrc cannot open !\n");/*GUI_SetColor(GUI_BLUE);GUI_SetBkColor(GUI_GREEN);GUI_ClearRect(0, 160, 319, 184);GUI_SetFont(&GUI_FontHZ24);GUI_SetTextAlign(GUI_TA_HCENTER);GUI_DispStringAt("没找到相应的歌词!", 160, 160);*/sleep(1);continue ;}if(get_lrc_Info(fp, ply_info.time_s, &lrc_info) == 0){fseek(fp,lrc_info.offset,SEEK_SET);bzero(str, sizeof(str));fread(str, 1, lrc_info.length, fp);fseek(fp,lrc_info.offset,SEEK_SET);/*i = 0;while(lrc_info.length){lrc_info.length--;fread(&data, 1, 1, fp);printf("%c", data);i++;}*/str[lrc_info.length]= '\0';GUI_SetColor(GUI_BLUE);GUI_SetBkColor(GUI_GREEN);GUI_ClearRect(0, 160, 319, 184);GUI_SetFont(&GUI_FontHZ24);GUI_SetTextAlign(GUI_TA_HCENTER);GUI_DispStringAt(str, 160, 160);PROGBAR_SetValue(ahProgBar,get_ratio());//printf("ratio:%d**********\n", get_ratio());} fclose(fp);sleep(1);}return ((void *)1);
}
歌词同步进程,ucgui显示汉子要添加hzk24.c字库,具体方法添加hzk24.c到ucGUI的font目录下,然后调用Disp_String_At函数即可,歌词的编码要改为ascii格式,因为unicode是不可以的,这样就能动态的显示汉字了,折腾好久才发现这里的原因。
void *touch_thread(void *arg)
{struct tsdev *ts;GUI_PID_STATE state;int retval;int x, y;unsigned int i;struct ts_sample samp;char *tsdevice = NULL;static unsigned last_state = 0;printf("touch_thread begin, pid:%d\n",getpid());if((tsdevice = getenv("TSLIB_TSDEVICE")) == NULL){tsdevice = strdup("/dev/input/event0");}ts = ts_open(tsdevice, 0);if(!ts){printf("open error\n");return ((void *)1);}if(ts_config(ts)){perror("ts_config");return ((void *)1); }while(1){retval = ts_read(ts, &samp, 1); if(retval != 1)continue;printf("%6d %6d %6d\n", samp.x, samp.y, samp.pressure);state.x = samp.x;state.y = samp.y;state.Pressed = samp.pressure;if(state.Pressed != last_state){printf("there have a key pressed!\n");GUI_PID_StoreState(&state);last_state = state.Pressed;}}return ((void *)1);}
触摸线程
void *exec_thread(void *arg)
{printf("exec_thread for touch screen,pid:%d\n", getpid());for(;;){GUI_Exec();usleep(200);}return ((void *)1);
}
ucGUI执行线程
void *socket_thread(void *arg)
{struct sockaddr_in server_addr;int opt = 1, ret;int listen_socket = -1;fd_set rfds;struct timeval tv;server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htons(INADDR_ANY);server_addr.sin_port = htons(6666);listen_socket = socket(PF_INET,SOCK_STREAM,0);if( listen_socket < 0){printf("Create Socket Failed!");exit(1);}setsockopt(listen_socket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));setsockopt(listen_socket,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt));if(bind(listen_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))){printf("Server Bind Port Failed!"); exit(1);}if(listen(listen_socket, 5)){printf("Server Listen Failed!"); exit(1);}while (1){FD_ZERO(&rfds);if (listen_socket >= 0) {FD_SET(listen_socket, &rfds);}ret = select(listen_socket + 1, &rfds, NULL, NULL, &tv);if (ret <= 0)continue;if (listen_socket >= 0 && FD_ISSET(listen_socket, &rfds)) {if (server_fd >= 0) {shutdown(server_fd, SHUT_RDWR);}server_fd = accept(listen_socket, NULL, 0);printf("socket success!\n");}}return ((void *)1);
}
服务器端socket线程
int main(int argc, char *argv) {int fd;int err;volatile int keyvalue, i, count, j;struct input_event ev;pthread_t tid1, tid2, tid3, tid4, tid5;void *tret;DIR *dir;struct dirent *ptr;char *p = NULL;int n = 0;char name[MAX_NUM][NAME_LEN];pnode node_tmp;err = pthread_create(&tid1, NULL, touch_thread, NULL);err = pthread_create(&tid2, NULL, exec_thread, NULL);err = pthread_create(&tid3, NULL, socket_thread, NULL);sleep(1);err = pthread_create(&tid4, NULL, ctrl_thread, NULL);err = pthread_create(&tid5, NULL, lrc_thread, NULL);if(chdir("/mymusic") < 0)perror("chdir");if((dir = opendir("/mymusic")) == NULL){perror("opendir");exit(EXIT_FAILURE);}while((ptr = readdir(dir)) != NULL){if((p=strstr(ptr->d_name, ".mp3")) != NULL){strcpy(name[n++], ptr->d_name);}}cur_head = create_list(name, n);print_list(cur_head);for(;;){play(cur_head);sleep(1);}pthread_join(tid1, &tret);pthread_join(tid2, &tret);pthread_join(tid3, &tret);pthread_join(tid4, &tret);pthread_join(tid5, &tret);closedir(dir);close(fd);return 0;
}
主进程整整两天过去了,看着自己的劳动成果有一点小小的欣慰,但是频谱的是虚拟的,本来想分析源码从底层取出数据做FFT变换,但是这段时间在找工作,没有太大的精力去完成,今天的面试题有一个shell脚本的,可惜笔者时间久没看了,做的不好。
来张图片吧
有的东西看着很难但只要你做就会有成果,有的东西看着很简单当你做的时候也许会遇到很多问题,高手就是从遇到问题解决问题走过来的。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
