rockbox/apps/plugins/lib/mul_id3.c

175 lines
5.7 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2023 Christian Soffke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "mul_id3.h"
struct multiple_tracks_id3 {
unsigned long long filesize;
unsigned long long length;
unsigned long frequency;
unsigned int artist_hash;
unsigned int composer_hash;
unsigned int albumartist_hash;
unsigned int grouping_hash;
unsigned int comment_hash;
unsigned int album_hash;
unsigned int genre_hash;
unsigned int codectype;
unsigned int bitrate;
int year;
bool vbr;
};
static struct multiple_tracks_id3 mul_id3;
/* Calculate modified FNV hash of string
* has good avalanche behaviour and uniform distribution
* see http://home.comcast.net/~bretm/hash/ */
static unsigned int mfnv(char *str)
{
const unsigned int p = 16777619;
unsigned int hash = 0x811C9DC5; // 2166136261;
if (!str)
return 0;
while(*str)
hash = (hash ^ *str++) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
static void init_mul_id3(void)
{
mul_id3.artist_hash = 0;
mul_id3.album_hash = 0;
mul_id3.genre_hash = 0;
mul_id3.composer_hash = 0;
mul_id3.albumartist_hash = 0;
mul_id3.grouping_hash = 0;
mul_id3.comment_hash = 0;
mul_id3.codectype = 0;
mul_id3.vbr = false;
mul_id3.bitrate = 0;
mul_id3.frequency = 0;
mul_id3.length = 0;
mul_id3.filesize = 0;
mul_id3.year = 0;
}
void collect_id3(struct mp3entry *id3, bool is_first_track)
{
if (is_first_track)
{
init_mul_id3();
mul_id3.artist_hash = mfnv(id3->artist);
mul_id3.album_hash = mfnv(id3->album);
mul_id3.genre_hash = mfnv(id3->genre_string);
mul_id3.composer_hash = mfnv(id3->composer);
mul_id3.albumartist_hash = mfnv(id3->albumartist);
mul_id3.grouping_hash = mfnv(id3->grouping);
mul_id3.comment_hash = mfnv(id3->comment);
mul_id3.codectype = id3->codectype;
mul_id3.vbr = id3->vbr;
mul_id3.bitrate = id3->bitrate;
mul_id3.frequency = id3->frequency;
mul_id3.year = id3->year;
}
else
{
if (mul_id3.artist_hash && (mfnv(id3->artist) != mul_id3.artist_hash))
mul_id3.artist_hash = 0;
if (mul_id3.album_hash && (mfnv(id3->album) != mul_id3.album_hash))
mul_id3.album_hash = 0;
if (mul_id3.genre_hash && (mfnv(id3->genre_string) != mul_id3.genre_hash))
mul_id3.genre_hash = 0;
if (mul_id3.composer_hash && (mfnv(id3->composer) != mul_id3.composer_hash))
mul_id3.composer_hash = 0;
if (mul_id3.albumartist_hash && (mfnv(id3->albumartist) !=
mul_id3.albumartist_hash))
mul_id3.albumartist_hash = 0;
if (mul_id3.grouping_hash && (mfnv(id3->grouping) != mul_id3.grouping_hash))
mul_id3.grouping_hash = 0;
if (mul_id3.comment_hash && (mfnv(id3->comment) != mul_id3.comment_hash))
mul_id3.comment_hash = 0;
if (mul_id3.codectype && (id3->codectype != mul_id3.codectype))
mul_id3.codectype = AFMT_UNKNOWN;
if (mul_id3.bitrate && (id3->bitrate != mul_id3.bitrate ||
id3->vbr != mul_id3.vbr))
mul_id3.bitrate = 0;
if (mul_id3.frequency && (id3->frequency != mul_id3.frequency))
mul_id3.frequency = 0;
if (mul_id3.year && (id3->year != mul_id3.year))
mul_id3.year = 0;
}
mul_id3.length += id3->length;
mul_id3.filesize += id3->filesize;
}
/* (!) Note scale factor applied to returned metadata:
* - Unit for filesize will be KiB instead of Bytes
* - Unit for length will be s instead of ms
*
* Use result only as input for browse_id3,
* with the track_ct parameter set to > 1.
*/
void finalize_id3(struct mp3entry *id3)
{
id3->path[0] = '\0';
id3->title = NULL;
if (!mul_id3.artist_hash)
id3->artist = NULL;
if (!mul_id3.album_hash)
id3->album = NULL;
if (!mul_id3.genre_hash)
id3->genre_string = NULL;
if (!mul_id3.composer_hash)
id3->composer = NULL;
if (!mul_id3.albumartist_hash)
id3->albumartist = NULL;
if (!mul_id3.grouping_hash)
id3->grouping = NULL;
if (!mul_id3.comment_hash)
id3->comment = NULL;
id3->disc_string = NULL;
id3->track_string = NULL;
id3->year_string = NULL;
id3->year = mul_id3.year;
mul_id3.length /= 1000;
mul_id3.filesize >>= 10;
id3->length = mul_id3.length > ULONG_MAX ? 0 : mul_id3.length;
id3->filesize = mul_id3.filesize > INT_MAX ? 0 : mul_id3.filesize;
id3->frequency = mul_id3.frequency;
id3->bitrate = mul_id3.bitrate;
id3->codectype = mul_id3.codectype;
id3->vbr = mul_id3.vbr;
id3->discnum = 0;
id3->tracknum = 0;
id3->track_level = 0;
id3->album_level = 0;
}