Linux中c语言歌词解析

// main.c
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>

struct lrc
{                    // 定义一个链表串起时间和歌词
  int time;          // 时间
  char lrc_buf[200]; // 歌词
  int lrc_num;       // 第几句歌词
  struct lrc *next;  // 链表的指针
};
typedef struct lrc LRC;                                  // 结构体重定义
extern char *open_file();                                // 打开文件函数
extern int strtok_deal(char *f, char **song_line);       // 歌词切割函数
extern void four_deal(char **song_line, char *four[50]); // 对于前四行特殊处理
extern LRC *init();                                      // 确定链表头指针
extern void insert(LRC *p, LRC **head);
extern LRC *divide_deal(char **song_line, int n); // 分开时间与歌词
extern void time_delay(int sec);                  // 时间延迟
extern void set_fg_color(int color);              // 设置前景颜色
extern void clear_screen(void);                   // 清屏函数
extern void set_bg_color(int color);              // 设置背景颜色
extern void song_print(LRC *head, char **four);   // 歌词打印+效果
char *open_file()
{
  FILE *fp;
  fp = fopen("../简单爱.lrc", "rb");
  if (fp == NULL)
  {
    printf("NULL!\n");
    return 0;
  }
  fseek(fp, 0L, SEEK_END); // 光标定位
  int len = ftell(fp);     // 读取字节以便申请空间
  rewind(fp);
  char *f = (char *)malloc(len);
  fread(f, len, 1, fp); // 读取
  return f;
}
int strtok_deal(char *f, char **song_line)
{
  char *temp = NULL;
  int k = 0;
  temp = strtok(f, "\r\n"); // 遇‘\r''\n'切割
  while (temp)
  {
    song_line[k++] = temp; // 每行读入
    temp = strtok(NULL, "\r\n");
  }
  return k;
}

void four_deal(char **song_line, char *four[50])
{
  int i;
  for (i = 0; i < 4; i++)
  {
    char *temp = strtok(song_line[i], "[]"); // 遇'[]'的切割
    four[i] = temp;
  }
}

LRC *init()
{
  LRC *p = (LRC *)malloc(sizeof(LRC));
  p = NULL;
  p->next = NULL;
  return p;
}
void insert(LRC *p, LRC **head)
{ // 一边构建链表一边排序(对链表要求较高)
  if (*head == NULL)
  {
    *head = p;
    return;
  }
  LRC *temp = *head, *mid = *head;
  while (temp->next && temp->time < p->time)
  {
    mid = temp;
    temp = temp->next;
  }
  if (temp->time >= p->time)
  {
    p->next = temp;
    mid->next = p;
    return;
  }
  else
  {
    temp->next = p;
    p->next = NULL;
    return;
  }
}

LRC *divide_deal(char **song_line, int n)
{
  char song[100][100], mid[100][100] = {0};
  char *temp;
  LRC *head = NULL;
  int  k = 0, i, m = 0, q = 0;
  for (i = 0; i < n; i++)
  {
    temp = strtok(song_line[i], "[]");
    while (temp)
    {
      strcpy(mid[k++], temp);
      temp = strtok(NULL, "[]");
    }
  }
  for (i = 0; i < k; i++)
  {
    if (!isdigit(mid[i][0]))
    {
      strcpy(song[q++], mid[i]);
    }
  }
  int j = 0;
  for (i = 0; i < k; i++)
  {
    if (isdigit(*mid[i]))
    {
      char hh[5], mm[5], ss[5];
      LRC *p = (LRC *)malloc(sizeof(LRC));
      p->time = sscanf(mid[i], "%2s:%2s.%2s", hh, mm, ss);
      // 这种格式可以让时间以标准形式输出
      p->time = atoi(hh) * 60 + atoi(mm);
      // 将时间转化为秒存储到链表中
      p->lrc_num = ++m;
      strcpy(p->lrc_buf, song[j]);
      insert(p, &head); // 找准时机,插入链表
    }
    else
      j++;
  }
  return head;
}
void time_delay(int sec)
{
  int s_time, e_time;
  s_time = time(NULL);
  while (1)
  {
    e_time = time(NULL);
    if (e_time == s_time + sec)
      break;
  }
}
void clear_screen(void)
{
  printf("\033[2J");
  fflush(stdout);
}
void set_fg_color(int color)
{
  printf("\033[%dm", color);
  fflush(stdout);
}
void set_bg_color(int color)
{
  printf("\033[%dm", (color + 10));
  fflush(stdout);
}
void cusor_moveto(int x, int y)
{
  printf("\033[%d;%dH", y, x);
  fflush(stdout);
}
/*// 函数名:song_print
// 参数:
//   - head: LRC结构体指针,指向歌曲链表的头部
//   - four: 字符串数组指针,包含要打印的歌曲信息
// 返回值:无*/
void song_print(LRC *head, char **four)
{
  int num = 0, y = 0;                     // 初始化歌曲编号和纵坐标
  LRC *p_mov = head;                      // 指向当前歌曲的指针
  LRC *p_mov2;                            // 用于遍历歌曲链表的临时指针
  LRC *p_mov_front = head, *p_mov_front2; // 指向链表中的前一个和当前歌曲的指针
  int i, flag = 0;                        // 循环计数器和标志位
  while (1)
  {                 // 无限循环,直到链表结束或打印完所有歌曲的信息
    clear_screen(); // 清空屏幕
    y = 1;// 设置纵坐标为1,表示第一行开始打印歌词
    for (i = 0; i < 4; i++)// 打印歌手、歌曲名、时长和歌词信息
    {
      cusor_moveto(34, y++);// 移动光标到第i行的起始位置
      printf("\t\t\t\t\t%s\n", four[i]);// 打印字符串元素
    }
    cusor_moveto(34, y++);// 移动光标到第5行的起始位置,准备打印下一行的时间信息
    printf("\t\t\t\t\t  %02d:%02d\n", num / 60, num % 60); // 打印时间信息(分钟:秒)
    if (flag < 4)// 如果还没有打印完四行信息,则将指针移动到链表头部
      p_mov_front = head;
    if (num == p_mov->time)// 如果当前歌曲的时间与上一首歌相同,则继续遍历下一首
    {
      p_mov = p_mov->next;// 移动指针到下一首歌
      flag++;// 标记已经遍历了一首新歌
      if (flag > 4)// 如果已经遍历了四首新歌,则将指针移动回链表头部,以便重新开始遍历
        p_mov_front = p_mov_front->next;
    }
    p_mov2 = p_mov;// 保存当前歌曲的指针,以备后面遍历时使用
    p_mov_front2 = p_mov_front;// 保存前一个歌曲的指针,以备后面遍历时使用
    while (p_mov_front2 != p_mov)// 遍历链表中的所有歌曲,并打印出每首歌曲的歌词
    {
      cusor_moveto(60, y++);// 移动光标到歌词行的起始位置,准备打印歌词内容
      printf("\t%s\n", p_mov_front2->lrc_buf);// 打印歌词内容(假设为字符串)
      p_mov_front2 = p_mov_front2->next;// 移动指针到下一首歌词所在的歌曲
    }
    for (i = 0; i < 5; i++)// 如果还有更多的歌曲需要打印,则继续遍历并打印歌词
    {
      if (i == 0)// 设置前景色和背景色,以便区分不同歌曲的歌词显示效果
      {
        set_fg_color(31);// 设置前景色为蓝色(31)
        set_bg_color(30);// 设置背景色为黑色(30)
      }
      else
      {
        set_fg_color(37); // 设置前景色为白色(37)
        set_bg_color(30);// 设置背景色为黑色(30)
      }
      if (p_mov2 != NULL)
      {
        cusor_moveto(60, y++); // 光标控制
        printf("\t%s\n", p_mov2->lrc_buf);
        p_mov2 = p_mov2->next;
      }
    }
    if (p_mov == NULL)
      break;
    time_delay(1);
    num++;
  }
}
// void playMusic(char* musicFilename) {
//     char command[100];
//     sprintf(command, "mplayer %s", musicFilename);
//     system(command);
// }
void mplayer_play(char *mplayer_play)
{
  pid_t pid;
  pid = fork();
  if (pid < 0)
  {
    perror("fork");
  }
  else if (pid == 0)
  {
    close(1);
    close(2);
    execlp("mplayer", "mplayer", "-slave", "-quiet", mplayer_play, NULL);
    exit(0);
  }
  else
  {
    return;
  }
}
int main()
{
  char *temp = NULL;
  char *song_line[100];
  int line_num, i;
  char *four[50];
  temp = open_file(); // open_file 打开文件
  LRC *head = NULL;
  line_num = strtok_deal(temp, song_line); // hang_strtok
  four_deal(song_line, four);
  line_num -= 4;
  for (i = 0; i < line_num; i++)
  {
    song_line[i] = song_line[i + 4];
  }
  head = divide_deal(song_line, line_num);
  mplayer_play("../简单爱.mp3");
  song_print(head, four);
  return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值