Example #1
0
void input_mpg123::read_metadata()
{
    mpg123_scan(handle);
    int meta = mpg123_meta_check(handle);

    if (!(meta & MPG123_ID3)) {
        return;
    }

    mpg123_id3v1 *v1;
    mpg123_id3v2 *v2;

    if (mpg123_id3(handle, &v1, &v2) != MPG123_OK) {
        return;
    }

    if (v2) {
        title = decode_string<unc::utf8>(v2->title);
        artist = decode_string<unc::utf8>(v2->artist);
        album = decode_string<unc::utf8>(v2->album);
        year = decode_string<unc::utf8>(v2->year);
        return;
    }

    if (v1) {
        title = decode_byte_string<unc::latin1>(v1->title);
        artist = decode_byte_string<unc::latin1>(v1->artist);
        album = decode_byte_string<unc::latin1>(v1->album);
        year = decode_byte_string<unc::latin1>(v1->year);
        return;
    }
}
Example #2
0
int
in_mp3_getinfo(void *m, track_t *track)
{
#if 0
	int		meta;
	mpg123_id3v2	*v2;
	mpg123_id3v1	*v1;

	v1 = NULL;
	v2 = NULL;

	/* move those to some global string db */
	info->artist = "Unknown Artist";
	info->title = "Unknown Title";

	mpg123_scan(m);
	meta = mpg123_meta_check(m);
	/* XXX - generalize this, toooooooo ugly */
	if ((meta & MPG123_ID3) && (mpg123_id3(m, &v1, &v2) == MPG123_OK)) {
		if (v1 != NULL) {
			info->artist = (char *)malloc(31);
			strncpy(info->artist, v1->artist, 30);

			if (info->artist[30]) {
				info->artist = realloc(info->artist, 31);
				assert(info->artist != NULL);
				info->artist[31] = '\0';
			}

			info->title = (char *)malloc(31);
			strncpy(info->title, v1->title, 30);

			if (info->title[30]) {
				info->title = realloc(info->title, 31);
				assert(info->title != NULL);
				info->title[31] = '\0';
			}
		}
		if (v2 != NULL) {
			if (v2->artist != NULL) {
				info->artist = (char *)malloc(v2->artist->size + 2);
				strncpy(info->artist, v2->artist->p, v2->artist->size);

				if (info->artist[v2->artist->size]) {
					info->artist[v2->artist->size + 1] = '\0';
				}
			}
			if (v2->title != NULL) {
				info->title = (char *)malloc(v2->title->size + 2);
				strncpy(info->title, v2->title->p, v2->title->size);

				if (info->title[v2->title->size]) {
					info->title[v2->title->size + 1] = '\0';
				}
			}
		}
	}
#endif
	return REPLAY_ERR;
}
Example #3
0
    void MP3InputStream::GetID3()
    {
        mpg123_id3v1 *v1;
        mpg123_id3v2 *v2;
        std::string k, v, t;
        char b[32];

        if (mpg123_id3(mh,&v1,&v2) == MPG123_OK)
        {
            if (v1)
            {
                t = "ID3v1";
                k = "title"; memcpy(b,v1->title,30); b[30] = 0; v = b; addTag(k,v,t);
                k = "artist"; memcpy(b,v1->artist,30); b[30] = 0; v = b; addTag(k,v,t);
                k = "album"; memcpy(b,v1->album,30); b[30] = 0; v = b; addTag(k,v,t);
                k = "comment"; memcpy(b,v1->comment,30); b[30] = 0; v = b; addTag(k,v,t);
                k = "year"; memcpy(b,v1->year,4); b[4] = 0; v = b; addTag(k,v,t);
                k = "genre"; v = getGenre(v1->genre); addTag(k,v,t);
            }

            if (v2)
            {
                t = "ID3v2";
                k = "title"; GetMpg123String(v2->title,v); addTag(k,v,t);
                k = "artist"; GetMpg123String(v2->artist,v); addTag(k,v,t);
                k = "album"; GetMpg123String(v2->album,v); addTag(k,v,t);
                k = "year"; GetMpg123String(v2->year,v); addTag(k,v,t);
                k = "genre"; GetMpg123String(v2->genre,v); addTag(k,v,t);
                k = "comment"; GetMpg123String(v2->comment,v); addTag(k,v,t);
            }
        }
    }
Example #4
0
void generic_sendalltag(mpg123_handle *mh)
{
    mpg123_id3v1 *v1;
    mpg123_id3v2 *v2;
    generic_sendmsg("T {");
    if(MPG123_OK != mpg123_id3(mh, &v1, &v2))
    {
        error1("Cannot get ID3 data: %s", mpg123_strerror(mh));
        v2 = NULL;
        v1 = NULL;
    }
    if(v1 != NULL) generic_sendv1(v1, "T");

    if(v2 != NULL)
    {
        size_t i;
        for(i=0; i<v2->texts; ++i)
        {
            char id[5];
            memcpy(id, v2->text[i].id, 4);
            id[4] = 0;
            generic_sendmsg("T ID3v2.%s:", id);
            generic_send_lines("T =%s", &v2->text[i].text);
        }
        for(i=0; i<v2->extras; ++i)
        {
            char id[5];
            memcpy(id, v2->extra[i].id, 4);
            id[4] = 0;
            generic_sendmsg("T ID3v2.%s desc(%s):",
                            id,
                            v2->extra[i].description.fill ? v2->extra[i].description.p : "" );
            generic_send_lines("T =%s", &v2->extra[i].text);
        }
        for(i=0; i<v2->comments; ++i)
        {
            char id[5];
            char lang[4];
            memcpy(id, v2->comment_list[i].id, 4);
            id[4] = 0;
            memcpy(lang, v2->comment_list[i].lang, 3);
            lang[3] = 0;
            generic_sendmsg("T ID3v2.%s lang(%s) desc(%s):",
                            id, lang,
                            v2->comment_list[i].description.fill ? v2->comment_list[i].description.p : "");
            generic_send_lines("T =%s", &v2->comment_list[i].text);
        }
    }
    generic_sendmsg("T }");
}
Example #5
0
int main(int argc, char **argv)
{
	int err;
	int ret = 0;
	mpg123_handle *mh;
	mpg123_id3v2 *id3;

	if(argc < 2)
	{
		printf("Gimme a MPEG file name...\n");
		return 0;
	}

	mpg123_init();
	mh = mpg123_new(NULL, &err);
	if(err != MPG123_OK) goto badend;

	mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_PLAIN_ID3TEXT, 0.);

	err = mpg123_open(mh, argv[1]);
	if(err != MPG123_OK) goto badend;

	err = mpg123_scan(mh);
	if(err != MPG123_OK) goto badend;

	err = mpg123_id3(mh, NULL, &id3);
	if(err != MPG123_OK) goto badend;

	if(id3 == NULL)
	{
		error("No ID3 data found.");
		goto badend;
	}

	print_field("artist", id3->artist);
	print_field("title", id3->title);
	print_field("album", id3->album);
	print_field("comment", id3->comment);

	goto end;
badend:
	ret = -1;
end:
	mpg123_delete(mh);
	mpg123_exit();
	return ret;
}
Example #6
0
static void generic_sendinfoid3(mpg123_handle *mh)
{
    mpg123_id3v1 *v1;
    mpg123_id3v2 *v2;
    if(MPG123_OK != mpg123_id3(mh, &v1, &v2))
    {
        error1("Cannot get ID3 data: %s", mpg123_strerror(mh));
        return;
    }
    if(v1 != NULL)
    {
        generic_sendv1(v1, "I");
    }
    if(v2 != NULL)
    {
        generic_send_lines("I ID3v2.title:%s",   v2->title);
        generic_send_lines("I ID3v2.artist:%s",  v2->artist);
        generic_send_lines("I ID3v2.album:%s",   v2->album);
        generic_send_lines("I ID3v2.year:%s",    v2->year);
        generic_send_lines("I ID3v2.comment:%s", v2->comment);
        generic_send_lines("I ID3v2.genre:%s",   v2->genre);
    }
}
Example #7
0
int main(int argc, char **argv)
{
	int i, result;
	mpg123_handle* m;
#if defined(WANT_WIN32_UNICODE)
	win32_cmdline_utf8(&argc,&argv);
#endif
	progname = argv[0];

	while ((result = getlopt(argc, argv, opts)))
	switch (result) {
		case GLO_UNKNOWN:
			fprintf (stderr, "%s: Unknown option \"%s\".\n", 
				progname, loptarg);
			usage(1);
		case GLO_NOARG:
			fprintf (stderr, "%s: Missing argument for option \"%s\".\n",
				progname, loptarg);
			usage(1);
	}

#ifdef WIN32
	fprintf(stderr, "WARNING: This tool is not yet adapted to run on Windows (file I/O, unicode arguments)!\n");
#endif
	if(loptind >= argc) usage(1);

	mpg123_init();
	m = mpg123_new(NULL, NULL);
	mpg123_param(m, MPG123_ADD_FLAGS, MPG123_PICTURE, 0.);

	for(i=loptind; i < argc; ++i)
	{
		mpg123_id3v1 *v1;
		mpg123_id3v2 *v2;
		int meta;
		if(mpg123_open(m, argv[i]) != MPG123_OK)
		{
			fprintf(stderr, "Cannot open %s: %s\n", argv[i], mpg123_strerror(m));
			continue;
		}
		mpg123_scan(m);
		meta = mpg123_meta_check(m);
		if(meta & MPG123_ID3 && mpg123_id3(m, &v1, &v2) == MPG123_OK)
		{
			printf("FILE: %s\n", argv[i]);
			printf("\n====      ID3v1       ====\n");
			if(v1 != NULL) print_v1(v1);

			printf("\n====      ID3v2       ====\n");
			if(v2 != NULL) print_v2(v2);

			printf("\n==== ID3v2 Raw frames ====\n");
			if(v2 != NULL)
			{
				print_raw_v2(v2);
				if(param.store_pics)
				store_pictures(argv[i], v2);
			}
		}
		else printf("Nothing found for %s.\n", argv[i]);

		mpg123_close(m);
	}
	mpg123_delete(m);
	mpg123_exit();

	if(errors) error1("Encountered %i errors along the way.", errors);
	return errors != 0;
#if defined(WANT_WIN32_UNICODE)
	win32_cmdline_utf8_free(argc,argv);
#endif
}
Example #8
0
float* readaudio_mp3(const char *filename,long *sr, unsigned int *buflen,\
		     const float nbsecs, AudioMetaData *mdata, int *error){
  mpg123_handle *m;
  int ret = 0;
  mpg123_id3v1 *v1 = NULL;
  mpg123_id3v2 *v2 = NULL;

  if ((ret = mpg123_init()) != MPG123_OK || ((m = mpg123_new(NULL,&ret)) == NULL)|| \
      (ret = mpg123_open(m, filename)) != MPG123_OK){
    *error = (ret != 0) ? ret : PHERR_MP3NEW;
    return NULL;
  }

  /*turn off logging */
  mpg123_param(m, MPG123_ADD_FLAGS, MPG123_QUIET, 0);

  off_t totalsamples;
  
  mpg123_scan(m);
  totalsamples = mpg123_length(m);
  if (totalsamples <= 0){
    *error = PHERR_NOSAMPLES;
    return NULL;
  }
  
  int meta = mpg123_meta_check(m);

  if (mdata)init_mdata(mdata);
  if (mdata && (meta & MPG123_ID3) && mpg123_id3(m, &v1, &v2) == MPG123_OK){
    if (v2){
      get_v2_data(v2, mdata);
    } else if (v1){
      get_v1_data(v1, mdata);
    } 
  }

  int channels, encoding;
    
  if (mpg123_getformat(m, sr, &channels, &encoding) != MPG123_OK){
    *error = PHERR_NOFORMAT;
    return NULL;
  }
  
  mpg123_format_none(m);
  mpg123_format(m, *sr, channels, encoding);
  if (channels <= 0 || encoding <= 0){
    *error = PHERR_NOENCODING;
    return NULL;
  }


  size_t decbuflen = mpg123_outblock(m);
  if (decbuflen == 0){
    /* take a guess */ 
    decbuflen = 1<<16;
  }

  unsigned char *decbuf = (unsigned char*)malloc(decbuflen);  
  if (decbuf == NULL){
    *error = PHERR_MEMALLOC;
    return NULL;
  }

  unsigned int nbsamples = (nbsecs <= 0) ? totalsamples : nbsecs*(*sr);
  nbsamples = (nbsamples <= totalsamples) ? nbsamples : totalsamples;

  size_t i, j, index = 0, done;


  float *buffer = (float*)malloc(nbsamples*sizeof(float));
  if (buffer == NULL){
    *error = PHERR_MEMALLOC;
    return NULL;
  }
  *buflen = nbsamples;

  do {
    ret = mpg123_read(m, decbuf, decbuflen, &done);
    switch (encoding) {
    case MPG123_ENC_SIGNED_16 :
      for (i = 0; i < done/sizeof(short); i+=channels){
	buffer[index] = 0.0f;
	for (j = 0; j < channels ; j++){
	  buffer[index] += (float)(((short*)decbuf)[i+j])/(float)SHRT_MAX;
	}
	buffer[index++] /= channels;
	if (index >= nbsamples) break;
      }
      break;
    case MPG123_ENC_SIGNED_8:
      for (i = 0; i < done/sizeof(char); i+=channels){
	buffer[index] = 0.0f;
	for (j = 0; j < channels ; j++){
	  buffer[index] += (float)(((char*)decbuf)[i+j])/(float)SCHAR_MAX;
	}
	buffer[index++] /= channels;
	if (index >= nbsamples) break;
      }
      break;
    case MPG123_ENC_FLOAT_32:
      for (i = 0; i < done/sizeof(float); i+=channels){
	buffer[index] = 0.0f;
	for (j = 0; j < channels; j++){
	  buffer[index] += ((float*)decbuf)[i+j];
	}
	buffer[index++] /= channels;
	if (index >= nbsamples) break;
      }
      break;
    default:
	done = 0;
    }

  } while (ret == MPG123_OK && index < nbsamples);

  if (ret != MPG123_DONE && ret != MPG123_OK && index < nbsamples){
    free(buffer);
    *error = ret;
    buffer=NULL;
  }
  free(decbuf);
  mpg123_close(m);
  mpg123_delete(m);
  mpg123_exit();

  return buffer;
}
/* Print tags... limiting the UTF-8 to ASCII, if necessary. */
void print_id3_tag(mpg123_handle *mh, int long_id3, FILE *out)
{
	char genre_from_v1 = 0;
	enum tagcode ti;
	mpg123_string tag[FIELDS];
	size_t len[FIELDS];
	mpg123_id3v1 *v1;
	mpg123_id3v2 *v2;
	/* no memory allocated here, so return is safe */
	for(ti=0; ti<FIELDS; ++ti){ len[ti]=0; mpg123_init_string(&tag[ti]); }
	/* extract the data */
	mpg123_id3(mh, &v1, &v2);
	/* Only work if something there... */
	if(v1 == NULL && v2 == NULL) return;
	if(v2 != NULL) /* fill from ID3v2 data */
	{
		len[TITLE]   = transform(&tag[TITLE],   v2->title);
		len[ARTIST]  = transform(&tag[ARTIST],  v2->artist);
		len[ALBUM]   = transform(&tag[ALBUM],   v2->album);
		len[COMMENT] = transform(&tag[COMMENT], v2->comment);
		len[YEAR]    = transform(&tag[YEAR],    v2->year);
		len[GENRE]   = transform(&tag[GENRE],   v2->genre);
	}
	if(v1 != NULL) /* fill gaps with ID3v1 data */
	{
		/* I _could_ skip the recalculation of fill ... */
		id3_gap(&tag[TITLE],   30, v1->title,   &len[TITLE]);
		id3_gap(&tag[ARTIST],  30, v1->artist,  &len[ARTIST]);
		id3_gap(&tag[ALBUM],   30, v1->album,   &len[ALBUM]);
		id3_gap(&tag[COMMENT], 30, v1->comment, &len[COMMENT]);
		id3_gap(&tag[YEAR],    4,  v1->year,    &len[YEAR]);
		/*
			genre is special... v1->genre holds an index, id3v2 genre may contain indices in textual form and raw textual genres...
		*/
		if(!tag[GENRE].fill)
		{
			if(tag[GENRE].size >= 31 || mpg123_resize_string(&tag[GENRE],31))
			{
				if(v1->genre <= genre_count)
				{
					strncpy(tag[GENRE].p, genre_table[v1->genre], 30);
				}
				else
				{
					strncpy(tag[GENRE].p,"Unknown",30);
				}
				tag[GENRE].p[30] = 0;
				/* V1 was plain ASCII, so strlen is fine. */
				len[GENRE] = strlen(tag[GENRE].p);
				tag[GENRE].fill = len[GENRE] + 1;
				genre_from_v1 = 1;
			}
		}
	}

	if(tag[GENRE].fill && !genre_from_v1)
	{
		/*
			id3v2.3 says (id)(id)blabla and in case you want ot have (blabla) write ((blabla)
			also, there is
			(RX) Remix
			(CR) Cover
			id3v2.4 says
			"one or several of the ID3v1 types as numerical strings"
			or define your own (write strings), RX and CR 

			Now I am very sure that I'll encounter hellishly mixed up id3v2 frames, so try to parse both at once.
		*/
		mpg123_string tmp;
		mpg123_init_string(&tmp);
		debug1("interpreting genre: %s\n", tag[GENRE].p);
		if(mpg123_copy_string(&tag[GENRE], &tmp))
		{
			size_t num = 0;
			size_t nonum = 0;
			size_t i;
			enum { nothing, number, outtahere } state = nothing;
			tag[GENRE].fill = 0; /* going to be refilled */
			/* number\n -> id3v1 genre */
			/* (number) -> id3v1 genre */
			/* (( -> ( */
			for(i = 0; i < tmp.fill; ++i)
			{
				debug1("i=%lu", (unsigned long) i);
				switch(state)
				{
					case nothing:
						nonum = i;
						if(tmp.p[i] == '(')
						{
							num = i+1; /* number starting as next? */
							state = number;
							debug1("( before number at %lu?", (unsigned long) num);
						}
						/* you know an encoding where this doesn't work? */
						else if(tmp.p[i] >= '0' && tmp.p[i] <= '9')
						{
							num = i;
							state = number;
							debug1("direct number at %lu", (unsigned long) num);
						}
						else state = outtahere;
					break;
					case number:
						/* fake number alert: (( -> ( */
						if(tmp.p[i] == '(')
						{
							nonum = i;
							state = outtahere;
							debug("no, it was ((");
						}
						else if(tmp.p[i] == ')' || tmp.p[i] == '\n' || tmp.p[i] == 0)
						{
							if(i-num > 0)
							{
								/* we really have a number */
								int gid;
								char* genre = "Unknown";
								tmp.p[i] = 0;
								gid = atoi(tmp.p+num);

								/* get that genre */
								if(gid >= 0 && gid <= genre_count) genre = genre_table[gid];
								debug1("found genre: %s", genre);

								if(tag[GENRE].fill) mpg123_add_string(&tag[GENRE], ", ");
								mpg123_add_string(&tag[GENRE], genre);
								nonum = i+1; /* next possible stuff */
								state = nothing;
								debug1("had a number: %i", gid);
							}
							else
							{
								/* wasn't a number, nonum is set */
								state = outtahere;
								debug("no (num) thing...");
							}
						}
						else if(!(tmp.p[i] >= '0' && tmp.p[i] <= '9'))
						{
							/* no number at last... */
							state = outtahere;
							debug("nothing numeric here");
						}
						else
						{
							debug("still number...");
						}
					break;
					default: break;
				}
				if(state == outtahere) break;
			}
			if(nonum < tmp.fill-1)
			{
				if(tag[GENRE].fill) mpg123_add_string(&tag[GENRE], ", ");
				mpg123_add_string(&tag[GENRE], tmp.p+nonum);
			}
			/* Do not like that ... assumes plain ASCII ... */
			len[GENRE] = strlen(tag[GENRE].p);
		}
		mpg123_free_string(&tmp);
	}

	if(long_id3)
	{
		fprintf(out,"\n");
		/* print id3v2 */
		print_oneline(out, tag, TITLE,   TRUE);
		print_oneline(out, tag, ARTIST,  TRUE);
		print_oneline(out, tag, ALBUM,   TRUE);
		print_oneline(out, tag, YEAR,    TRUE);
		print_oneline(out, tag, GENRE,   TRUE);
		print_oneline(out, tag, COMMENT, TRUE);
		fprintf(out,"\n");
	}
	else
	{
		/* We are trying to be smart here and conserve some vertical space.
		   So we will skip tags not set, and try to show them in two parallel
		   columns if they are short, which is by far the most common case. */
		int linelimit;
		/* Overhead is Name + ": " and also plus "  " for right column. */
		const int overhead[2] = { namelen[0]+2, namelen[1]+4 };
		int climit[2];

		/* Adapt formatting width to terminal if possible. */
		linelimit = term_width(fileno(out));
		if(linelimit < 0)
			linelimit=overhead[0]+30+overhead[1]+30; /* the old style, based on ID3v1 */
		if(linelimit > 200)
			linelimit = 200; /* Not too wide. Also for format string safety. */
		/* Divide the space between the two columns, not wasting any. */
		climit[1] = linelimit/2-overhead[0];
		climit[0] = linelimit-linelimit/2-overhead[1];
		debug3("linelimits: %i  < %i | %i >", linelimit, climit[0], climit[1]);

		if(climit[0] <= 0 || climit[1] <= 0)
		{
			/* Ensure disabled column printing, no play with signedness in comparisons. */
			climit[0] = 0;
			climit[1] = 0;
		}
		fprintf(out,"\n"); /* Still use one separator line. Too ugly without. */
		print_pair(out, climit, tag, len, TITLE,   ARTIST);
		print_pair(out, climit, tag, len, COMMENT, ALBUM );
		print_pair(out, climit, tag, len, YEAR,    GENRE );
	}
	for(ti=0; ti<FIELDS; ++ti) mpg123_free_string(&tag[ti]);

	if(v2 != NULL && APPFLAG(MPG123APP_LYRICS))
	{
		/* find and print texts that have USLT IDs */
		size_t i;
		for(i=0; i<v2->texts; ++i)
		{
			if(!memcmp(v2->text[i].id, "USLT", 4))
			{
				/* split into lines, ensure usage of proper local line end */
				size_t a=0;
				size_t b=0;
				char lang[4]; /* just a 3-letter ASCII code, no fancy encoding */
				mpg123_string innline;
				mpg123_string outline;
				mpg123_string *uslt = &v2->text[i].text;

				memcpy(lang, &v2->text[i].lang, 3);
				lang[3] = 0;
				printf("Lyrics begin, language: %s; %s\n\n", lang,  v2->text[i].description.fill ? v2->text[i].description.p : "");

				mpg123_init_string(&innline);
				mpg123_init_string(&outline);
				while(a < uslt->fill)
				{
					b = a;
					while(b < uslt->fill && uslt->p[b] != '\n' && uslt->p[b] != '\r') ++b;
					/* Either found end of a line or end of the string (null byte) */
					mpg123_set_substring(&innline, uslt->p, a, b-a);
					transform(&outline, &innline);
					printf(" %s\n", outline.p);

					if(uslt->p[b] == uslt->fill) break; /* nothing more */

					/* Swallow CRLF */
					if(uslt->fill-b > 1 && uslt->p[b] == '\r' && uslt->p[b+1] == '\n') ++b;

					a = b + 1; /* next line beginning */
				}
				mpg123_free_string(&innline);
				mpg123_free_string(&outline);

				printf("\nLyrics end.\n");
			}
		}
	}
}
Example #10
0
/* print tags... limiting the UTF-8 to ASCII */
void print_id3_tag(mpg123_handle *mh, int long_id3, FILE *out)
{
    char genre_from_v1 = 0;
    enum { TITLE=0, ARTIST, ALBUM, COMMENT, YEAR, GENRE, FIELDS } ti;
    mpg123_string tag[FIELDS];
    size_t len[FIELDS];
    mpg123_id3v1 *v1;
    mpg123_id3v2 *v2;
    /* no memory allocated here, so return is safe */
    for(ti=0; ti<FIELDS; ++ti) mpg123_init_string(&tag[ti]);
    /* extract the data */
    mpg123_id3(mh, &v1, &v2);
    /* Only work if something there... */
    if(v1 == NULL && v2 == NULL) return;
    if(v2 != NULL) /* fill from ID3v2 data */
    {
        len[TITLE]   = transform(&tag[TITLE],   v2->title);
        len[ARTIST]  = transform(&tag[ARTIST],  v2->artist);
        len[ALBUM]   = transform(&tag[ALBUM],   v2->album);
        len[COMMENT] = transform(&tag[COMMENT], v2->comment);
        len[YEAR]    = transform(&tag[YEAR],    v2->year);
        len[GENRE]   = transform(&tag[GENRE],   v2->genre);
    }
    if(v1 != NULL) /* fill gaps with ID3v1 data */
    {
        /* I _could_ skip the recalculation of fill ... */
        id3_gap(&tag[TITLE],   30, v1->title,   &len[TITLE]);
        id3_gap(&tag[ARTIST],  30, v1->artist,  &len[ARTIST]);
        id3_gap(&tag[ALBUM],   30, v1->album,   &len[ALBUM]);
        id3_gap(&tag[COMMENT], 30, v1->comment, &len[COMMENT]);
        id3_gap(&tag[YEAR],    4,  v1->year,    &len[YEAR]);
        /*
        	genre is special... v1->genre holds an index, id3v2 genre may contain indices in textual form and raw textual genres...
        */
        if(!tag[GENRE].fill)
        {
            if(tag[GENRE].size >= 31 || mpg123_resize_string(&tag[GENRE],31))
            {
                if(v1->genre <= genre_count)
                {
                    strncpy(tag[GENRE].p, genre_table[v1->genre], 30);
                }
                else
                {
                    strncpy(tag[GENRE].p,"Unknown",30);
                }
                tag[GENRE].p[30] = 0;
                tag[GENRE].fill = strlen(tag[GENRE].p) + 1;
                genre_from_v1 = 1;
            }
        }
    }

    if(tag[GENRE].fill && !genre_from_v1)
    {
        /*
        	id3v2.3 says (id)(id)blabla and in case you want ot have (blabla) write ((blabla)
        	also, there is
        	(RX) Remix
        	(CR) Cover
        	id3v2.4 says
        	"one or several of the ID3v1 types as numerical strings"
        	or define your own (write strings), RX and CR

        	Now I am very sure that I'll encounter hellishly mixed up id3v2 frames, so try to parse both at once.
        */
        mpg123_string tmp;
        mpg123_init_string(&tmp);
        debug1("interpreting genre: %s\n", tag[GENRE].p);
        if(mpg123_copy_string(&tag[GENRE], &tmp))
        {
            size_t num = 0;
            size_t nonum = 0;
            size_t i;
            enum { nothing, number, outtahere } state = nothing;
            tag[GENRE].fill = 0; /* going to be refilled */
            /* number\n -> id3v1 genre */
            /* (number) -> id3v1 genre */
            /* (( -> ( */
            for(i = 0; i < tmp.fill; ++i)
            {
                debug1("i=%lu", (unsigned long) i);
                switch(state)
                {
                case nothing:
                    nonum = i;
                    if(tmp.p[i] == '(')
                    {
                        num = i+1; /* number starting as next? */
                        state = number;
                        debug1("( before number at %lu?", (unsigned long) num);
                    }
                    /* you know an encoding where this doesn't work? */
                    else if(tmp.p[i] >= '0' && tmp.p[i] <= '9')
                    {
                        num = i;
                        state = number;
                        debug1("direct number at %lu", (unsigned long) num);
                    }
                    else state = outtahere;
                    break;
                case number:
                    /* fake number alert: (( -> ( */
                    if(tmp.p[i] == '(')
                    {
                        nonum = i;
                        state = outtahere;
                        debug("no, it was ((");
                    }
                    else if(tmp.p[i] == ')' || tmp.p[i] == '\n' || tmp.p[i] == 0)
                    {
                        if(i-num > 0)
                        {
                            /* we really have a number */
                            int gid;
                            char* genre = "Unknown";
                            tmp.p[i] = 0;
                            gid = atoi(tmp.p+num);

                            /* get that genre */
                            if(gid >= 0 && gid <= genre_count) genre = genre_table[gid];
                            debug1("found genre: %s", genre);

                            if(tag[GENRE].fill) mpg123_add_string(&tag[GENRE], ", ");
                            mpg123_add_string(&tag[GENRE], genre);
                            nonum = i+1; /* next possible stuff */
                            state = nothing;
                            debug1("had a number: %i", gid);
                        }
                        else
                        {
                            /* wasn't a number, nonum is set */
                            state = outtahere;
                            debug("no (num) thing...");
                        }
                    }
                    else if(!(tmp.p[i] >= '0' && tmp.p[i] <= '9'))
                    {
                        /* no number at last... */
                        state = outtahere;
                        debug("nothing numeric here");
                    }
                    else
                    {
                        debug("still number...");
                    }
                    break;
                default:
                    break;
                }
                if(state == outtahere) break;
            }
            if(nonum < tmp.fill-1)
            {
                if(tag[GENRE].fill) mpg123_add_string(&tag[GENRE], ", ");
                mpg123_add_string(&tag[GENRE], tmp.p+nonum);
            }
            /* Do not like that ... assumes plain ASCII ... */
            len[GENRE] = strlen(tag[GENRE].p);
        }
        mpg123_free_string(&tmp);
    }

    if(long_id3)
    {
        fprintf(out,"\n");
        /* print id3v2 */
        /* dammed, I use pointers as bool again! It's so convenient... */
        fprintf(out,"\tTitle:   %s\n", tag[TITLE].fill ? tag[TITLE].p : "");
        fprintf(out,"\tArtist:  %s\n", tag[ARTIST].fill ? tag[ARTIST].p : "");
        fprintf(out,"\tAlbum:   %s\n", tag[ALBUM].fill ? tag[ALBUM].p : "");
        fprintf(out,"\tYear:    %s\n", tag[YEAR].fill ? tag[YEAR].p : "");
        fprintf(out,"\tGenre:   %s\n", tag[GENRE].fill ? tag[GENRE].p : "");
        fprintf(out,"\tComment: %s\n", tag[COMMENT].fill ? tag[COMMENT].p : "");
        fprintf(out,"\n");
    }
    else
    {
        char space[31];
        size_t i;
        space[30] = 0;
        for(i=0; i<30; ++i) space[i] = ' ';

        /* We are trying to be smart here and conserve vertical space.
           So we will skip tags not set, and try to show them in two parallel columns if they are short, which is by far the	most common case. */
        /* one _could_ circumvent the strlen calls... */
        if(tag[TITLE].fill && tag[ARTIST].fill && len[TITLE] <= 30 && len[TITLE] <= 30)
        {
            fprintf(out,"Title:   %s%s  Artist: %s\n",tag[TITLE].p, space+len[TITLE], tag[ARTIST].p);
        }
        else
        {
            if(tag[TITLE].fill) fprintf(out,"Title:   %s\n", tag[TITLE].p);
            if(tag[ARTIST].fill) fprintf(out,"Artist:  %s\n", tag[ARTIST].p);
        }
        if(tag[COMMENT].fill && tag[ALBUM].fill && len[COMMENT] <= 30 && len[ALBUM] <= 30)
        {
            fprintf(out,"Comment: %s%s  Album:  %s\n",tag[COMMENT].p, space+len[COMMENT], tag[ALBUM].p);
        }
        else
        {
            if(tag[COMMENT].fill)
                fprintf(out,"Comment: %s\n", tag[COMMENT].p);
            if(tag[ALBUM].fill)
                fprintf(out,"Album:   %s\n", tag[ALBUM].p);
        }
        if(tag[YEAR].fill && tag[GENRE].fill && len[YEAR] <= 30 && len[GENRE] <= 30)
        {
            fprintf(out,"Year:    %s%s  Genre:  %s\n",tag[YEAR].p, space+len[YEAR], tag[GENRE].p);
        }
        else
        {
            if(tag[YEAR].fill)
                fprintf(out,"Year:    %s\n", tag[YEAR].p);
            if(tag[GENRE].fill)
                fprintf(out,"Genre:   %s\n", tag[GENRE].p);
        }
    }
    for(ti=0; ti<FIELDS; ++ti) mpg123_free_string(&tag[ti]);
}
Example #11
0
bool getMusInfo( mpg123_handle *mus, long *r, int *c, QString *_t, QString *T, QString *A, int type, const char *fileE )
{
	if ( mus )
	{
		int chn(0),e(0);
		long rate(0);
		mpg123_getformat(mus, &rate, &chn, &e);

		if ( rate == 0 || chn == 0 )
			return false;

		if ( type < 0 )
			return true;

		if ( r )
			*r = rate;
		if( c )
			*c = chn;
	}
	else if ( !type )
		return false;

	QString Title, Artist, t;

	if ( ( type == 0 || ( type == 2 && knownSize ) ) && ( _t || T || A ) )
	{
		if ( tag_editor && type == 0 )
		{
			QString data = tag_editor->getData( fileE, NULL );
			if ( !data.isEmpty() )
			{
				Title = getTagFromData( data, "Title" );
				Artist = getTagFromData( data, "Artist" );
			}
		}
		else //jeżeli biblioteka do ID3 nie została załadowana
		{
			mpg123_id3v1 *v1;
			mpg123_id3v2 *v2;
			mpg123_id3(mus, &v1, &v2);
			mpg123_id3(mus, &v1, &v2);

			if ( v2 != NULL )
			{
				if ( v2->title && v2->title->p )
					Title  = v2->title->p;
				if ( v2->artist && v2->artist->p )
					Artist = v2->artist->p;
			}
			if ( v1 != NULL )
			{
				if ( Artist.isEmpty() )
					Artist = v1->artist;
				if ( Title.isEmpty() )
					Title  = v1->title;
			}
		}

		if ( !Title.isEmpty() )
		{
			t = Title;
			if ( !Artist.isEmpty() )
				t = Artist + " - " + Title;
		}
	}
	if ( type == 2 && !knownSize )
	{
		Title = getTitle();
		if (mus)
		{
			char *a = getICYName( data, _DATA_BUFF );
			if (a)
				Artist = a;
			delete[] a;
		}
		else if (A)
			Artist = *A;

		if ( !Title.isEmpty() )
			t += Title;
		if ( !Title.isEmpty() && !Artist.isEmpty() )
			t += " - "+Artist;
		if ( !Artist.isEmpty() && Title.isEmpty() )
			t += Artist;
	}

	if ( _t )
		*_t = t;
	if ( T )
		*T = Title;
	if ( A )
		*A = Artist;

	return true;
}