Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions
+94
View File
@@ -0,0 +1,94 @@
#include "AACFrame.h"
#include "api__in_mp3.h"
#include "resource.h"
#include "in2.h"
extern In_Module mod;
void AACFrame::ReadBuffer( unsigned __int8 *buffer )
{
syncword = ( buffer[ 0 ] << 4 ) | ( buffer[ 1 ] >> 4 );
id = ( buffer[ 1 ] >> 3 ) & 1;
layer = ( buffer[ 1 ] >> 1 ) & 3;
protection = ( buffer[ 1 ] ) & 1;
profile = ( buffer[ 2 ] >> 6 ) & 3;
sampleRateIndex = ( buffer[ 2 ] >> 2 ) & 0xF;
privateBit = ( buffer[ 2 ] >> 1 ) & 1;
channelConfiguration = ( ( buffer[ 2 ] & 1 ) << 2 ) | ( ( buffer[ 3 ] >> 6 ) & 3 );
original = ( buffer[ 3 ] >> 5 ) & 1;
home = ( buffer[ 3 ] >> 4 ) & 1;
//copyright_identification_bit = (buffer[3] >> 3) & 1;
//copyright_identification_start = (buffer[3] >> 2) & 1;
frameLength = ( ( buffer[ 3 ] & 3 ) << 11 ) | ( buffer[ 4 ] << 3 ) | ( ( buffer[ 5 ] >> 5 ) & 7 );
bufferFullness = ( ( buffer[ 5 ] & 0xF8 ) << 5 ) | ( ( buffer[ 6 ] >> 2 ) & 0x3F );
numDataBlocks = buffer[ 6 ] & 3;
}
bool AACFrame::OK()
{
if (syncword == SYNC
&& layer == 0
&& sampleRateIndex < 13
//&& profile != LTP // TODO: can coding technologies decoder do LTP?
)
return true;
else
return false;
}
static const unsigned int aac_sratetab[] =
{
96000,
88200,
64000,
48000,
44100,
32000,
24000,
22050,
16000,
12000,
11025,
8000,
7350,
};
int AACFrame::GetSampleRate()
{
return aac_sratetab[sampleRateIndex];
}
static const wchar_t *aac_profiletab[] = {L"Main", L"LC", L"SSR", L"LTP"};
const wchar_t *AACFrame::GetProfileName()
{
return aac_profiletab[profile];
}
//static const char *aac_channels[] = {"Custom", "Mono", "Stereo", "3 channel", "4 channel", "surround", "5.1", "7.1"};
static wchar_t aac_channels_str[64];
static int aac_channels_id[] = {IDS_CUSTOM, IDS_MONO, IDS_STEREO, IDS_3_CHANNEL, IDS_4_CHANNEL, IDS_SURROUND, IDS_5_1, IDS_7_1};
const wchar_t *AACFrame::GetChannelConfigurationName()
{
return WASABI_API_LNGSTRINGW_BUF(aac_channels_id[channelConfiguration],aac_channels_str,64);
}
int AACFrame::GetNumChannels()
{
switch(channelConfiguration)
{
case 7:
return 8;
default:
return channelConfiguration;
}
}
int AACFrame::GetMPEGVersion()
{
if (id == 0)
return 2;
else
return 4;
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef NULLSOFT_AACFRAME_H
#define NULLSOFT_AACFRAME_H
class AACFrame
{
public:
void ReadBuffer(unsigned __int8 *buffer);
bool OK();
enum
{
NOT_PROTECTED=1,
PROTECTED=0,
SYNC = 0xFFF,
MAIN = 0x00,
LC = 0x01,
SSR = 0x10,
LTP = 0x11,
};
int GetNumChannels();
int GetSampleRate();
const wchar_t *GetProfileName();
const wchar_t *GetChannelConfigurationName();
int GetMPEGVersion(); // returns 2 or 4
public:
int syncword;
int layer;
int id;
int protection;
int profile;
int sampleRateIndex;
int privateBit;
int channelConfiguration;
int original;
int home;
int frameLength;
int bufferFullness;
int numDataBlocks;
};
#endif
+283
View File
@@ -0,0 +1,283 @@
#include "main.h"
#include "Metadata.h"
#include "api__in_mp3.h"
#include "../nu/AutoWide.h"
#include "AlbumArt.h"
#include "Stopper.h"
#include <shlwapi.h>
#include <strsafe.h>
bool IsMyExtension(const wchar_t *filename)
{
// check if it's the current stream and is playing and is SHOUTcast2
if (PathIsURLW(filename))
{
if (g_playing_file)
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file &&
(g_playing_file->uvox_artwork.uvox_stream_artwork || g_playing_file->uvox_artwork.uvox_playing_artwork) &&
!lstrcmpW(lastfn, filename)) // check again now that we've acquired the lock
{
LeaveCriticalSection(&streamInfoLock);
return true;
}
LeaveCriticalSection(&streamInfoLock);
}
}
// otherwise handle as normal embedded
else
{
const wchar_t *extension = PathFindExtension(filename);
if (extension && *extension)
{
AutoWide wideList(config_extlist); // TODO: build a copy of this at config load time so we don't have to run this every time
extension++;
wchar_t *b = wideList;
wchar_t *c = 0;
do
{
wchar_t d[20] = {0};
StringCchCopyW(d, 15, b);
if ((c = wcschr(b, L';')))
{
if ((c-b)<15)
d[c - b] = 0;
}
if (!lstrcmpiW(extension, d))
return true;
b = c + 1;
}
while (c);
}
}
return false;
}
bool ID3v2_AlbumArtProvider::IsMine(const wchar_t *filename)
{
return IsMyExtension(filename);
}
int ID3v2_AlbumArtProvider::ProviderType()
{
return ALBUMARTPROVIDER_TYPE_EMBEDDED;
}
int ID3v2_AlbumArtProvider::GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType)
{
if (g_playing_file)
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file && !lstrcmpW(lastfn, filename)) // check again now that we've acquired the lock
{
wchar_t* mimeType[] = {
L"image/jpeg",
L"image/png",
L"image/bmp",
L"image/gif"
};
if (!g_playing_file->uvox_artwork.uvox_stream_artwork)
{
int ret = g_playing_file->info.GetAlbumArt(type, bits, len, mimeType);
LeaveCriticalSection(&streamInfoLock);
return ret;
}
else
{
// will handle "playing" and "cover" - cover is the stream branding
// with "playing" used to provide song specific stream artwork
if (!_wcsicmp(type, L"playing"))
{
if (g_playing_file->uvox_artwork.uvox_playing_artwork_len > 0)
{
*len = g_playing_file->uvox_artwork.uvox_playing_artwork_len;
int type = g_playing_file->uvox_artwork.uvox_playing_artwork_type;
if(type >= 0 && type <= 3)
{
*mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(12 * sizeof(wchar_t));
wcsncpy(*mimeType, mimeType[type], 12);
}
else
{
*mimeType = 0;
}
*bits = WASABI_API_MEMMGR->sysMalloc(*len);
memcpy(*bits, g_playing_file->uvox_artwork.uvox_playing_artwork, *len);
LeaveCriticalSection(&streamInfoLock);
return ALBUMARTPROVIDER_SUCCESS;
}
else
{
LeaveCriticalSection(&streamInfoLock);
return ALBUMARTPROVIDER_FAILURE;
}
}
else
{
if (g_playing_file->uvox_artwork.uvox_stream_artwork_len > 0)
{
*len = g_playing_file->uvox_artwork.uvox_stream_artwork_len;
int type = g_playing_file->uvox_artwork.uvox_stream_artwork_type;
if(type >= 0 && type <= 3)
{
*mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(12 * sizeof(wchar_t));
wcsncpy(*mimeType, mimeType[type], 12);
}
else
{
*mimeType = 0;
}
*bits = WASABI_API_MEMMGR->sysMalloc(*len);
memcpy(*bits, g_playing_file->uvox_artwork.uvox_stream_artwork, *len);
LeaveCriticalSection(&streamInfoLock);
return ALBUMARTPROVIDER_SUCCESS;
}
else
{
LeaveCriticalSection(&streamInfoLock);
return ALBUMARTPROVIDER_FAILURE;
}
}
}
}
LeaveCriticalSection(&streamInfoLock);
}
Metadata metadata;
if (metadata.Open(filename) == METADATA_SUCCESS)
{
return metadata.id3v2.GetAlbumArt(type, bits, len, mimeType);
}
return ALBUMARTPROVIDER_FAILURE;
}
extern Metadata *m_ext_get_mp3info;
int ID3v2_AlbumArtProvider::SetAlbumArtData(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType)
{
Metadata metadata;
if (metadata.Open(filename) == METADATA_SUCCESS)
{
int ret = metadata.id3v2.SetAlbumArt(type, bits, len, mimeType);
if (ret == METADATA_SUCCESS)
{
// flush our read cache too :)
if (m_ext_get_mp3info) m_ext_get_mp3info->Release();
m_ext_get_mp3info = NULL;
Stopper stopper;
if (metadata.IsMe(lastfn))
stopper.Stop();
metadata.Save();
stopper.Play();
}
return ret;
}
return ALBUMARTPROVIDER_FAILURE;
}
int ID3v2_AlbumArtProvider::DeleteAlbumArt(const wchar_t *filename, const wchar_t *type)
{
Metadata metadata;
if (metadata.Open(filename) == METADATA_SUCCESS)
{
int ret = metadata.id3v2.DeleteAlbumArt(type);
if (ret == METADATA_SUCCESS)
{
// flush our read cache too :)
if (m_ext_get_mp3info) m_ext_get_mp3info->Release();
m_ext_get_mp3info = NULL;
Stopper stopper;
if (metadata.IsMe(lastfn))
stopper.Stop();
metadata.Save();
stopper.Play();
}
return ret;
}
return ALBUMARTPROVIDER_FAILURE;
}
#define CBCLASS ID3v2_AlbumArtProvider
START_DISPATCH;
CB(SVC_ALBUMARTPROVIDER_PROVIDERTYPE, ProviderType);
CB(SVC_ALBUMARTPROVIDER_GETALBUMARTDATA, GetAlbumArtData);
CB(SVC_ALBUMARTPROVIDER_ISMINE, IsMine);
CB(SVC_ALBUMARTPROVIDER_SETALBUMARTDATA, SetAlbumArtData);
CB(SVC_ALBUMARTPROVIDER_DELETEALBUMART, DeleteAlbumArt);
END_DISPATCH;
#undef CBCLASS
static ID3v2_AlbumArtProvider albumArtProvider;
// {C8222317-8F0D-4e79-9222-447381C46E07}
static const GUID id3v2_albumartproviderGUID =
{ 0xc8222317, 0x8f0d, 0x4e79, { 0x92, 0x22, 0x44, 0x73, 0x81, 0xc4, 0x6e, 0x7 } };
FOURCC AlbumArtFactory::GetServiceType()
{
return svc_albumArtProvider::SERVICETYPE;
}
const char *AlbumArtFactory::GetServiceName()
{
return "ID3v2 Album Art Provider";
}
GUID AlbumArtFactory::GetGUID()
{
return id3v2_albumartproviderGUID;
}
void *AlbumArtFactory::GetInterface(int global_lock)
{
return &albumArtProvider;
}
int AlbumArtFactory::SupportNonLockingInterface()
{
return 1;
}
int AlbumArtFactory::ReleaseInterface(void *ifc)
{
//plugin.service->service_unlock(ifc);
return 1;
}
const char *AlbumArtFactory::GetTestString()
{
return 0;
}
int AlbumArtFactory::ServiceNotify(int msg, int param1, int param2)
{
return 1;
}
#ifdef CBCLASS
#undef CBCLASS
#endif
#define CBCLASS AlbumArtFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;
+39
View File
@@ -0,0 +1,39 @@
#ifndef NULLSOFT_IN_MP3_ALBUMART_H
#define NULLSOFT_IN_MP3_ALBUMART_H
#include "../Agave/AlbumArt/svc_albumArtProvider.h"
class ID3v2_AlbumArtProvider : public svc_albumArtProvider
{
public:
bool IsMine(const wchar_t *filename);
int ProviderType();
// implementation note: use WASABI_API_MEMMGR to alloc bits and mimetype, so that the recipient can free through that
int GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType);
int SetAlbumArtData(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType);
int DeleteAlbumArt(const wchar_t *filename, const wchar_t *type);
protected:
RECVS_DISPATCH;
};
#include <api/service/waservicefactory.h>
#include <api/service/services.h>
class AlbumArtFactory : public waServiceFactory
{
public:
FOURCC GetServiceType();
const char *GetServiceName();
GUID GetGUID();
void *GetInterface(int global_lock);
int SupportNonLockingInterface();
int ReleaseInterface(void *ifc);
const char *GetTestString();
int ServiceNotify(int msg, int param1, int param2);
protected:
RECVS_DISPATCH;
};
#endif
+327
View File
@@ -0,0 +1,327 @@
//---------------------------------------------------------------------------\
//
// (C) copyright Fraunhofer - IIS (2000)
// All Rights Reserved
//
// filename: CVbriHeader.cpp
// MPEG Layer-3 Audio Decoder
// author : Martin Weishart martin.weishart@iis.fhg.de
// date : 2000-02-11
// contents/description: provides functions to read a VBRI header
// of a MPEG Layer 3 bitstream encoded
// with variable bitrate using Fraunhofer
// variable bitrate format
//
//--------------------------------------------------------------------------/
#include <windows.h>
#include "CVbriHeader.h"
#include "LAMEInfo.h"
#include <malloc.h>
//---------------------------------------------------------------------------\
//
// Constructor: set position in buffer to parse and create a
// VbriHeaderTable
//
//---------------------------------------------------------------------------/
CVbriHeader::CVbriHeader(){
position = 0;
VbriTable=0;
VbriStreamFrames=0;
encoderDelay=0;
h_id=0;
SampleRate=0;
VbriTableSize=0;
VbriEntryFrames=0;
VbriStreamBytes=0;
}
//---------------------------------------------------------------------------\
//
// Destructor: delete a VbriHeaderTable and a VbriHeader
//
//---------------------------------------------------------------------------/
CVbriHeader::~CVbriHeader(){
free(VbriTable);
}
//---------------------------------------------------------------------------\
//
// Method: checkheader
// Reads the header to a struct that has to be stored and is
// used in other functions to determine file offsets
// Input: buffer containing the first frame
// Output: fills struct VbriHeader
// Return: 0 on success; 1 on error
//
//---------------------------------------------------------------------------/
int CVbriHeader::readVbriHeader(unsigned char *Hbuffer)
{
position=0;
// MPEG header
MPEGFrame frame;
frame.ReadBuffer(Hbuffer);
if (!frame.IsSync())
return 0;
SampleRate = frame.GetSampleRate();
h_id = frame.mpegVersion & 1;
position += DWORD ;
// data indicating silence
position += (8*DWORD) ;
// if a VBRI Header exists read it
if ( *(Hbuffer+position ) == 'V' &&
*(Hbuffer+position+1) == 'B' &&
*(Hbuffer+position+2) == 'R' &&
*(Hbuffer+position+3) == 'I'){
position += DWORD;
//position += WORD;
/*unsigned int vbriVersion = */readFromBuffer(Hbuffer, WORD); // version
encoderDelay = readFromBuffer(Hbuffer, WORD); // delay
position += WORD;
//readFromBuffer(Hbuffer, WORD); // quality
VbriStreamBytes = readFromBuffer(Hbuffer, DWORD);
VbriStreamFrames = readFromBuffer(Hbuffer, DWORD);
VbriTableSize = readFromBuffer(Hbuffer, WORD);
unsigned int VbriTableScale = readFromBuffer(Hbuffer, WORD);
unsigned int VbriEntryBytes = readFromBuffer(Hbuffer, WORD);
VbriEntryFrames = readFromBuffer(Hbuffer, WORD);
if (VbriTableSize > 32768) return 1;
VbriTable = (int *)calloc((VbriTableSize + 1), sizeof(int));
for (unsigned int i = 0 ; i <= VbriTableSize ; i++){
VbriTable[i] = readFromBuffer(Hbuffer, VbriEntryBytes*BYTE)
* VbriTableScale ;
}
}
else
{
return 0;
}
return frame.FrameSize();
}
//---------------------------------------------------------------------------\
//
// Method: seekPointByTime
// Returns a point in the file to decode in bytes that is nearest
// to a given time in seconds
// Input: time in seconds
// Output: None
// Returns: point belonging to the given time value in bytes
//
//---------------------------------------------------------------------------/
int CVbriHeader::seekPointByTime(float EntryTimeInMilliSeconds){
unsigned int SamplesPerFrame, i=0, SeekPoint = 0 , fraction = 0;
float TotalDuration ;
float DurationPerVbriFrames ;
float AccumulatedTime = 0.0f ;
(SampleRate >= 32000) ? (SamplesPerFrame = 1152) : (SamplesPerFrame = 576) ;
TotalDuration = ((float)VbriStreamFrames * (float)SamplesPerFrame)
/ (float)SampleRate * 1000.0f ;
DurationPerVbriFrames = (float)TotalDuration / (float)(VbriTableSize+1) ;
if ( EntryTimeInMilliSeconds > TotalDuration ) EntryTimeInMilliSeconds = TotalDuration;
while ( AccumulatedTime <= EntryTimeInMilliSeconds ){
SeekPoint += VbriTable[i] ;
AccumulatedTime += DurationPerVbriFrames;
i++;
}
// Searched too far; correct result
fraction = ( (int)(((( AccumulatedTime - EntryTimeInMilliSeconds ) / DurationPerVbriFrames )
+ (1.0f/(2.0f*(float)VbriEntryFrames))) * (float)VbriEntryFrames));
SeekPoint -= (int)((float)VbriTable[i-1] * (float)(fraction)
/ (float)VbriEntryFrames) ;
return SeekPoint ;
}
int CVbriHeader::getNumMS()
{
if (!VbriStreamFrames || !SampleRate) return 0;
int nf=VbriStreamFrames;
int sr=SampleRate;
if (sr >= 32000) sr/=2;
//576
return MulDiv(nf,576*1000,sr);
}
#if 0
//---------------------------------------------------------------------------\
//
// Method: seekTimeByPoint
// Returns a time in the file to decode in seconds that is
// nearest to a given point in bytes
// Input: time in seconds
// Output: None
// Returns: point belonging to the given time value in bytes
//
//---------------------------------------------------------------------------/
float CVbriHeader::seekTimeByPoint(unsigned int EntryPointInBytes){
unsigned int SamplesPerFrame, i=0, AccumulatedBytes = 0, fraction = 0;
float SeekTime = 0.0f;
float TotalDuration ;
float DurationPerVbriFrames ;
(SampleRate >= 32000) ? (SamplesPerFrame = 1152) : (SamplesPerFrame = 576) ;
TotalDuration = ((float)VbriStreamFrames * (float)SamplesPerFrame)
/ (float)SampleRate;
DurationPerVbriFrames = (float)TotalDuration / (float)(VbriTableSize+1) ;
while (AccumulatedBytes <= EntryPointInBytes){
AccumulatedBytes += VbriTable[i] ;
SeekTime += DurationPerVbriFrames;
i++;
}
// Searched too far; correct result
fraction = (int)(((( AccumulatedBytes - EntryPointInBytes ) / (float)VbriTable[i-1])
+ (1/(2*(float)VbriEntryFrames))) * (float)VbriEntryFrames);
SeekTime -= (DurationPerVbriFrames * (float) ((float)(fraction) / (float)VbriEntryFrames)) ;
return SeekTime ;
}
//---------------------------------------------------------------------------\
//
// Method: seekPointByPercent
// Returns a point in the file to decode in bytes that is
// nearest to a given percentage of the time of the stream
// Input: percent of time
// Output: None
// Returns: point belonging to the given time percentage value in bytes
//
//---------------------------------------------------------------------------/
int CVbriHeader::seekPointByPercent(float percent){
int SamplesPerFrame;
float TotalDuration ;
if (percent >= 100.0f) percent = 100.0f;
if (percent <= 0.0f) percent = 0.0f;
(SampleRate >= 32000) ? (SamplesPerFrame = 1152) : (SamplesPerFrame = 576) ;
TotalDuration = ((float)VbriStreamFrames * (float)SamplesPerFrame)
/ (float)SampleRate;
return seekPointByTime( (percent/100.0f) * TotalDuration * 1000.0f );
}
#endif
//---------------------------------------------------------------------------\
//
// Method: GetSampleRate
// Returns the sampling rate of the file to decode
// Input: Buffer containing the part of the first frame after the
// syncword
// Output: None
// Return: sampling rate of the file to decode
//
//---------------------------------------------------------------------------/
/*int CVbriHeader::getSampleRate(unsigned char * buffer){
unsigned char id, idx, mpeg ;
id = (0xC0 & (buffer[1] << 3)) >> 4;
idx = (0xC0 & (buffer[2] << 4)) >> 6;
mpeg = id | idx;
switch ((int)mpeg){
case 0 : return 11025;
case 1 : return 12000;
case 2 : return 8000;
case 8 : return 22050;
case 9 : return 24000;
case 10: return 16000;
case 12: return 44100;
case 13: return 48000;
case 14: return 32000;
default: return 0;
}
}*/
//---------------------------------------------------------------------------\
//
// Method: readFromBuffer
// reads from a buffer a segment to an int value
// Input: Buffer containig the first frame
// Output: none
// Return: number containing int value of buffer segmenet
// length
//
//---------------------------------------------------------------------------/
int CVbriHeader::readFromBuffer ( unsigned char * HBuffer, int length ){
if (HBuffer)
{
int number = 0;
for(int i = 0; i < length ; i++ )
{
int b = length-1-i ;
number = number | (unsigned int)( HBuffer[position+i] & 0xff ) << ( 8*b );
}
position += length ;
return number;
}
else{
return 0;
}
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef _VBRIHEADER_H_
#define _VBRIHEADER_H_
class CVbriHeader{
public:
CVbriHeader();
~CVbriHeader();
int readVbriHeader(unsigned char *Hbuffer);
int seekPointByTime(float EntryTimeInSeconds);
#if 0
float seekTimeByPoint(unsigned int EntryPointInBytes);
int seekPointByPercent(float percent);
#endif
int getNumFrames() { return VbriStreamFrames; }
int getNumMS();
int getEncoderDelay() { return encoderDelay; }
int getBytes() { return VbriStreamBytes; }
int h_id;
private:
int getSampleRate(unsigned char * buffer);
int readFromBuffer ( unsigned char * HBuffer, int length );
int SampleRate;
unsigned int VbriStreamBytes;
unsigned int VbriStreamFrames;
unsigned int VbriTableSize;
unsigned int VbriEntryFrames;
int * VbriTable;
int encoderDelay;
int position ;
enum offset{
BYTE = 1,
WORD = 2,
DWORD = 4
};
};
#endif//_VBRIHEADER_H_
+6
View File
@@ -0,0 +1,6 @@
#ifndef NULLSOFT_CREATEFILEH
#define NULLSOFT_CREATEFILEH
#endif
+54
View File
@@ -0,0 +1,54 @@
/*---- DXhead.c --------------------------------------------
decoder MPEG Layer III
handle Xing header
mod 12/7/98 add vbr scale
Copyright 1998 Xing Technology Corp.
-----------------------------------------------------------*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <float.h>
#include <math.h>
#include "dxhead.h"
/*-------------------------------------------------------------*/
int SeekPoint(unsigned char TOC[100], int file_bytes, float percent)
{
// interpolate in TOC to get file seek point in bytes
int a, seekpoint;
float fa, fb, fx;
if (percent < 0.0f)
percent = 0.0f;
if (percent > 100.0f)
percent = 100.0f;
a = (int)percent;
if (a > 99) a = 99;
fa = TOC[a];
if (a < 99)
{
fb = TOC[a + 1];
}
else
{
fb = 256.0f;
}
fx = fa + (fb - fa) * (percent - a);
seekpoint = (int) ((1.0f / 256.0f) * fx * file_bytes);
return seekpoint;
}
/*-------------------------------------------------------------*/
+43
View File
@@ -0,0 +1,43 @@
/*---- DXhead.h --------------------------------------------
decoder MPEG Layer III
handle Xing header
Copyright 1998 Xing Technology Corp.
-----------------------------------------------------------*/
// A Xing header may be present in the ancillary
// data field of the first frame of an mp3 bitstream
// The Xing header (optionally) contains
// frames total number of audio frames in the bitstream
// bytes total number of bytes in the bitstream
// toc table of contents
// toc (table of contents) gives seek points
// for random access
// the ith entry determines the seek point for
// i-percent duration
// seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes
// e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes
#define FRAMES_FLAG 0x0001
#define BYTES_FLAG 0x0002
#define TOC_FLAG 0x0004
#define VBR_SCALE_FLAG 0x0008
#define FRAMES_AND_BYTES (FRAMES_FLAG | BYTES_FLAG)
int SeekPoint(unsigned char TOC[100], int file_bytes, float percent);
// return seekpoint in bytes (may be at eof if percent=100.0)
// TOC = table of contents from Xing header
// file_bytes = number of bytes in mp3 file
// percent = play time percentage of total playtime. May be
// fractional (e.g. 87.245)
+810
View File
@@ -0,0 +1,810 @@
#include "DecodeThread.h"
#include "giofile.h"
#include "main.h"
#include "pdtimer.h"
#include "mpegutil.h"
#include "../Winamp/wa_ipc.h"
#include "config.h"
#include <shlwapi.h>
#include "adts.h"
#include "adts_vlb.h"
#include <foundation/error.h>
// {19450308-90D7-4E45-8A9D-DC71E67123E2}
static const GUID adts_aac_guid =
{ 0x19450308, 0x90d7, 0x4e45, { 0x8a, 0x9d, 0xdc, 0x71, 0xe6, 0x71, 0x23, 0xe2 } };
// {4192FE3F-E843-445c-8D62-51BE5EE5E68C}
static const GUID adts_mp2_guid =
{ 0x4192fe3f, 0xe843, 0x445c, { 0x8d, 0x62, 0x51, 0xbe, 0x5e, 0xe5, 0xe6, 0x8c } };
extern int m_is_stream;
extern bool m_is_stream_seekable;
// post this to the main window at end of file (after playback as stopped)
#define WM_WA_MPEG_EOF WM_USER+2
/* public data */
int last_decode_pos_ms;
int decode_pos_ms; // current decoding position, in milliseconds.
volatile int seek_needed; // if != -1, it is the point that the decode
// thread should seek to, in ms.
int g_ds;
size_t g_bits;
int g_sndopened;
int g_bufferstat;
int g_length = -1000;
int g_vis_enabled;
volatile int g_closeaudio = 0;
CGioFile *g_playing_file=0;
/* private data */
static size_t g_samplebuf_used;
static int need_prebuffer;
static int g_srate, g_nch, g_br_add, g_br_div, g_avg_vbr_br;
int g_br;
class EndCutter
{
public:
EndCutter() : buffer(0), cutSize(0), filledSize(0), preCutSize(0), preCut(0), decoderDelay(0)
{}
~EndCutter()
{
free(buffer);
}
void SetEndSize(int postSize)
{
postSize -= decoderDelay;
if (postSize < 0)
postSize = 0;
else if (postSize)
{
free(buffer);
buffer = (char *)calloc(postSize, sizeof(char));
cutSize = postSize;
}
}
void SetSize(int decoderDelaySize, int preSize, int postSize)
{
decoderDelay = decoderDelaySize;
SetEndSize(postSize);
preCutSize = preSize;
preCut = preCutSize + decoderDelay;
}
void Flush(int time_in_ms)
{
if (time_in_ms == 0) // TODO: calculate actual delay if we seek within the encoder delay area
preCut = preCutSize; // reset precut size if we seek to the start
filledSize = 0;
mod.outMod->Flush(time_in_ms);
}
void Write(char *out, int outSize)
{
if (!out && (!outSize))
{
mod.outMod->Write(0, 0);
return ;
}
// cut pre samples, if necessary
int pre = min(preCut, outSize);
out += pre;
outSize -= pre;
preCut -= pre;
if (!outSize)
return ;
int remainingFill = cutSize - filledSize;
int fillWrite = min(outSize - remainingFill, filledSize); // only write fill buffer if we've got enough left to fill it up
if (fillWrite > 0)
{
mod.outMod->Write((char *)buffer, fillWrite);
if (cutSize - fillWrite)
memmove(buffer, buffer + fillWrite, cutSize - fillWrite);
filledSize -= fillWrite;
}
remainingFill = cutSize - filledSize;
int outWrite = max(0, outSize - remainingFill);
if (outWrite)
mod.outMod->Write((char *)out, outWrite);
out += outWrite;
outSize -= outWrite;
if (outSize)
{
memcpy(buffer + filledSize, out, outSize);
filledSize += outSize;
}
}
char *buffer;
int cutSize;
int filledSize;
int preCut, preCutSize, decoderDelay;
};
class DecodeLoop
{
public:
DecodeLoop() : decoder(0)
{
isAac = 0;
isEAAC = 0;
last_bpos = -1;
need_synclight = true;
done = 0;
br = 0;
g_framesize = 0;
maxlatency = 0;
sampleFrameSize = 0;
memset(&g_samplebuf, 0, sizeof(g_samplebuf));
}
~DecodeLoop()
{
if (decoder)
{
decoder->Close();
decoder->Release();
}
decoder=0;
}
DWORD Loop();
DWORD OpenDecoder();
void Seek(int seekPosition);
void PreBuffer();
void Decode();
void Viz();
void CalculateCodecDelay();
DWORD OpenOutput(int numChannels, int sampleRate, int bitsPerSample);
void SetupStream();
BYTE g_samplebuf[6*3*2*2*1152];
int g_framesize;
int isAac;
int isEAAC;
CGioFile file;
int maxlatency;
int last_bpos;
bool need_synclight;
int done; // set to TRUE if decoding has finished, 2 if all has been written
size_t br;
EndCutter endCutter;
int sampleFrameSize;
adts *decoder;
};
static int CalcPreBuffer(int buffer_setting, int bitrate)
{
if (bitrate < 8)
bitrate = 8;
else if (bitrate > 320)
bitrate = 320;
int prebuffer = (buffer_setting * bitrate) / 128;
if (prebuffer > 100)
prebuffer=100;
return prebuffer;
}
void DecodeLoop::SetupStream()
{
char buf[1024] = {0};
int len;
m_is_stream = file.IsStream();
//Wait until we have data...
while (!killDecodeThread && file.Peek(buf, 1024, &len) == NErr_Success && !len)
Sleep(50);
m_is_stream_seekable = file.IsStreamSeekable();
char *content_type = file.m_content_type;
if (content_type)
{
if (!_strnicmp(content_type, "misc/ultravox", 13))
{
switch (file.uvox_last_message)
{
case 0x8001:
case 0x8003:
isEAAC = 1;
isAac = 1;
break;
case 0x8000:
isAac = 1;
break;
}
}
else if (!_strnicmp(content_type, "audio/aac", 9))
{
isEAAC = 1;
isAac = 1;
}
else if (!_strnicmp(content_type, "audio/aacp", 10))
{
isEAAC = 1;
isAac = 1;
}
else if (!_strnicmp(content_type, "audio/apl", 10))
{
isEAAC = 1;
isAac = 1;
}
}
// todo: poll until connected to see if we get aac uvox frames or a content-type:aac header
}
DWORD DecodeLoop::OpenOutput(int numChannels, int sampleRate, int bitsPerSample)
{
maxlatency = mod.outMod->Open(sampleRate, numChannels, bitsPerSample, -1, -1);
// maxlatency is the maxium latency between a outMod->Write() call and
// when you hear those samples. In ms. Used primarily by the visualization
// system.
if (maxlatency < 0) // error opening device
{
PostMessage(mod.hMainWindow, WM_COMMAND, 40047, 0);
return 0;
}
g_sndopened = 1;
if (maxlatency == 0 && file.IsStream() == 2) // can't use with disk writer
{
if (!killDecodeThread)
{
EnterCriticalSection(&g_lfnscs);
WASABI_API_LNGSTRING_BUF(IDS_CANNOT_WRITE_STREAMS_TO_DISK,lastfn_status,256);
LeaveCriticalSection(&g_lfnscs);
PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
}
if (!killDecodeThread) Sleep(200);
if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
g_bufferstat = 0;
g_closeaudio = 1;
return 0;
}
if (paused) mod.outMod->Pause(1);
// set the output plug-ins default volume.
// volume is 0-255, -666 is a token for
// current volume.
mod.outMod->SetVolume(-666);
return 1;
}
void DecodeLoop::CalculateCodecDelay()
{
int decoderDelaySamples = (int)decoder->GetDecoderDelay();
endCutter.SetSize(decoderDelaySamples*sampleFrameSize,
file.prepad*sampleFrameSize,
file.postpad*sampleFrameSize);
}
void DecodeLoop::Viz()
{
if (!config_fastvis || (decoder->GetLayer() != 3 || g_ds))
{
int vis_waveNch;
int vis_specNch;
int csa = mod.SAGetMode();
int is_vis_running = mod.VSAGetMode(&vis_specNch, &vis_waveNch);
if (csa || is_vis_running)
{
int l = 576 * sampleFrameSize;
int ti = decode_pos_ms;
{
if (g_ds == 2)
{
memcpy(g_samplebuf + g_samplebuf_used, g_samplebuf, g_samplebuf_used);
}
size_t pos = 0;
while (pos < g_samplebuf_used)
{
int a, b;
if (mod.SAGetMode()) mod.SAAddPCMData((char *)g_samplebuf + pos, g_nch, (int)g_bits, ti);
if (mod.VSAGetMode(&a, &b)) mod.VSAAddPCMData((char *)g_samplebuf + pos, g_nch, (int)g_bits, ti);
ti += ((l / sampleFrameSize * 1000) / g_srate);
pos += l >> g_ds;
}
}
}
}
else
{
int l = (576 * (int)g_bits * g_nch);
int ti = decode_pos_ms;
size_t pos = 0;
int x = 0;
while (pos < g_samplebuf_used)
{
do_layer3_vis((short*)(g_samplebuf + pos), &g_vis_table[x++][0][0][0], g_nch, ti);
ti += (l / g_nch / 2 * 1000) / g_srate;
pos += l;
}
}
}
void DecodeLoop::Decode()
{
while (g_samplebuf_used < (size_t)g_framesize && !killDecodeThread && seek_needed == -1)
{
size_t newl = 0;
size_t br=0;
size_t endCut=0;
int res = decoder->Decode(&file, g_samplebuf + g_samplebuf_used, sizeof(g_samplebuf) / 2 - g_samplebuf_used, &newl, &br, &endCut);
if (config_gapless && endCut)
endCutter.SetEndSize((int)endCut* sampleFrameSize);
// we're not using switch here because we sometimes need to break out of the while loop
if (res == adts::SUCCESS)
{
if (!file.m_vbr_frames)
{
if (br) {
bool do_real_br=false;
if (!(config_miscopts&2) && br != decoder->GetCurrentBitrate())
{
do_real_br=true;
}
int r = (int)br;
g_br_add += r;
g_br_div++;
r = (g_br_add + g_br_div / 2) / g_br_div;
if (g_br != r)
{
need_synclight = false;
g_br = r;
if (!file.m_vbr_frames && file.IsSeekable()) g_length = MulDiv(file.GetContentLength(), 8, g_br);
if (!do_real_br)
mod.SetInfo(g_br, -1, -1, 1);
}
if (do_real_br)
mod.SetInfo((int)br, -1, -1, 1);
}
}
else
{
if (br) {
int r;
if (!(config_miscopts&2) || !g_avg_vbr_br)
r = (int)br;
else r = g_avg_vbr_br;
if (g_br != r)
{
need_synclight = false;
g_br = r;
mod.SetInfo(g_br, -1, -1, 1);
}
}
}
if (need_synclight)
{
need_synclight = false;
mod.SetInfo(-1, -1, -1, 1);
}
g_samplebuf_used += newl;
}
else if (res == adts::ENDOFFILE)
{
done = 1;
break;
}
else if (res == adts::NEEDMOREDATA)
{
if (file.IsStream() && !need_synclight)
{
need_synclight = true; mod.SetInfo(-1, -1, -1, 0);
}
if (file.IsStream() && !mod.outMod->IsPlaying())
{
need_prebuffer = CalcPreBuffer(config_http_prebuffer_underrun, (int)br);
}
break;
}
else
{
if (!need_synclight) mod.SetInfo(-1, -1, -1, 0);
need_synclight = true;
break;
}
}
}
void DecodeLoop::PreBuffer()
{
int p = file.RunStream();
int pa = file.PercentAvailable();
if (pa >= need_prebuffer || p == 2)
{
EnterCriticalSection(&g_lfnscs);
lastfn_status[0] = 0;
LeaveCriticalSection(&g_lfnscs);
PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
need_prebuffer = 0;
g_bufferstat = 0;
last_bpos = -1;
}
else
{
int bpos = pa * 100 / need_prebuffer;
if (!g_bufferstat) g_bufferstat = decode_pos_ms;
if (bpos != last_bpos)
{
last_bpos = bpos;
EnterCriticalSection(&g_lfnscs);
if (stricmp(lastfn_status, "stream temporarily interrupted"))
{
char langbuf[512] = {0};
wsprintfA(lastfn_status, WASABI_API_LNGSTRING_BUF(IDS_BUFFER_X,langbuf,512), bpos);
}
LeaveCriticalSection(&g_lfnscs);
int csa = mod.SAGetMode();
char tempdata[75*2] = {0, };
int x;
if (csa&1)
{
for (x = 0; x < bpos*75 / 100; x ++)
{
tempdata[x] = x * 16 / 75;
}
}
if (csa&2)
{
int offs = (csa & 1) ? 75 : 0;
x = 0;
while (x < bpos*75 / 100)
{
tempdata[offs + x++] = -6 + x * 14 / 75;
}
while (x < 75)
{
tempdata[offs + x++] = 0;
}
}
if (csa == 4)
{
tempdata[0] = tempdata[1] = (bpos * 127 / 100);
}
if (csa) mod.SAAdd(tempdata, ++g_bufferstat, (csa == 3) ? 0x80000003 : csa);
PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
}
}
}
void DecodeLoop::Seek(int seekPosition)
{
if (done == 3)
return;
done=0;
int br = (int)decoder->GetCurrentBitrate();
need_prebuffer = CalcPreBuffer(config_http_prebuffer_underrun, br);
if (need_prebuffer < 1) need_prebuffer = 5;
last_decode_pos_ms = decode_pos_ms = seekPosition;
seek_needed = -1;
endCutter.Flush(decode_pos_ms);
decoder->Flush(&file);
done = 0;
g_samplebuf_used = 0;
int r = g_br;
if (g_br_div) r = (g_br_add + g_br_div / 2) / g_br_div;
file.Seek(decode_pos_ms, r);
// need_prebuffer=config_http_prebuffer/8;
// g_br_add=g_br_div=0;
}
DWORD DecodeLoop::OpenDecoder()
{
mod.UsesOutputPlug &= ~8;
if (isAac)
{
if (isEAAC)
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(adts_aac_guid);
if (factory)
decoder = (adts *)factory->getInterface();
mod.UsesOutputPlug|=8;
}
if (!decoder)
{
decoder = new ADTS_VLB;
mod.UsesOutputPlug &= ~8;
}
}
else
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(adts_mp2_guid);
if (factory)
decoder = (adts *)factory->getInterface();
mod.UsesOutputPlug|=8;
}
if (decoder) {
decoder->SetDecoderHooks(mp3GiveVisData, mp2Equalize, mp3Equalize);
}
if (decoder
&& decoder->Initialize(AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false),
config_downmix == 2,
AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true),
(int)AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16), true, false,
(config_miscopts&1)/*crc*/) == adts::SUCCESS
&& decoder->Open(&file))
{
// sync to stream
while (1)
{
switch (decoder->Sync(&file, g_samplebuf, sizeof(g_samplebuf), &g_samplebuf_used, &br))
{
case adts::SUCCESS:
return 1;
case adts::FAILURE:
case adts::ENDOFFILE:
if (!killDecodeThread)
{
if (!lastfn_status_err)
{
EnterCriticalSection(&g_lfnscs);
WASABI_API_LNGSTRING_BUF(IDS_ERROR_SYNCING_TO_STREAM,lastfn_status,256);
LeaveCriticalSection(&g_lfnscs);
PostMessage(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE);
}
}
if (!killDecodeThread) Sleep(200);
if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
return 0;
case adts::NEEDMOREDATA:
if (!killDecodeThread && file.IsStream()) Sleep(25);
if (killDecodeThread) return 0;
}
}
}
return 0;
}
DWORD DecodeLoop::Loop()
{
last_decode_pos_ms = 0;
if (file.Open(lastfn, config_max_bufsize_k) != NErr_Success)
{
if (!killDecodeThread) Sleep(200);
if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
return 0;
}
if (file.IsSeekable()) mod.is_seekable = 1;
wchar_t *ext = PathFindExtension(lastfn);
if (!_wcsicmp(ext, L".aac")
|| !_wcsicmp(ext, L".vlb")
|| !_wcsicmp(ext, L".apl"))
{
if (file.IsStream())
SetupStream();
else
{
isAac = 1;
if (!_wcsicmp(ext, L".aac") || !_wcsicmp(ext, L".apl")) isEAAC = 1;
}
}
else if (file.IsStream())
SetupStream();
if (OpenDecoder() == 0)
return 0;
EnterCriticalSection(&streamInfoLock);
g_playing_file = &file;
if (file.uvox_3901)
{
PostMessage(mod.hMainWindow, WM_WA_IPC, (WPARAM) "0x3901", IPC_METADATA_CHANGED);
PostMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_UPDTITLE);
}
LeaveCriticalSection(&streamInfoLock);
EnterCriticalSection(&g_lfnscs);
lastfn_status[0] = 0;
LeaveCriticalSection(&g_lfnscs);
lastfn_data_ready = 1;
// TODO? if (decoder != &aacp) // hack because aac+ bitrate isn't accurate at this point
br = decoder->GetCurrentBitrate();
need_prebuffer = CalcPreBuffer(config_http_prebuffer, (int)br);
if (((!(config_eqmode&4) && decoder->GetLayer() == 3) ||
((config_eqmode&8) && decoder->GetLayer() < 3)))
{
mod.UsesOutputPlug |= 2;
}
else
mod.UsesOutputPlug &= ~2;
decoder->CalculateFrameSize(&g_framesize);
decoder->GetOutputParameters(&g_bits, &g_nch, &g_srate);
if (!killDecodeThread && file.IsStream() == 1)
{
DWORD_PTR dw;
if (!killDecodeThread) SendMessageTimeout(mod.hMainWindow, WM_USER, 0, IPC_UPDTITLE, SMTO_BLOCK, 100, &dw);
if (!killDecodeThread) SendMessageTimeout(mod.hMainWindow, WM_TIMER, 38, 0, SMTO_BLOCK, 100, &dw);
}
sampleFrameSize = g_nch * ((int)g_bits/8);
if (config_gapless)
CalculateCodecDelay();
if (OpenOutput(g_nch, g_srate, (int)g_bits) == 0)
return 0;
/* ----- send info to winamp and vis: bitrate, etc ----- */
g_br = (int)decoder->GetCurrentBitrate();
g_br_add = g_br;
g_br_div = 1;
g_avg_vbr_br = file.GetAvgVBRBitrate();
mod.SetInfo(g_br, g_srate / 1000, g_nch, 0);
// initialize visualization stuff
mod.SAVSAInit((maxlatency << g_ds), g_srate);
mod.VSASetInfo(g_srate, g_nch);
/* ----- end send info to winamp and vis ----- */
if (file.IsSeekable() && g_br)
{
mod.is_seekable = 1;
if (!file.m_vbr_frames) g_length = MulDiv(file.GetContentLength(), 8, g_br);
else g_length = file.m_vbr_ms;
}
if (file.IsStream())
{
if (need_prebuffer < config_http_prebuffer / 2)
need_prebuffer = config_http_prebuffer / 2;
}
while (!killDecodeThread)
{
if (seek_needed != -1)
Seek(seek_needed);
if (need_prebuffer && file.IsStream() && maxlatency && !file.EndOf())
PreBuffer();
int needsleep = 1;
if (done == 2) // done was set to TRUE during decoding, signaling eof
{
mod.outMod->CanWrite(); // some output drivers need CanWrite
// to be called on a regular basis.
if (!mod.outMod->IsPlaying())
{
// we're done playing, so tell Winamp and quit the thread.
if (!killDecodeThread) PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
done=3;
break;
}
}
else
{
int fs = (g_framesize * ((mod.dsp_isactive() == 1) ? 2 : 1));
// TODO: we should really support partial writes, there's no gaurantee that CanWrite() will EVER get big enough
if (mod.outMod->CanWrite() >= fs && (!need_prebuffer || !file.IsStream() || !maxlatency))
// CanWrite() returns the number of bytes you can write, so we check that
// to the block size. the reason we multiply the block size by two if
// mod.dsp_isactive() is that DSP plug-ins can change it by up to a
// factor of two (for tempo adjustment).
{
int p = mod.SAGetMode();
g_vis_enabled = ((p & 1) || p == 4);
if (!g_vis_enabled)
{
int s, a;
mod.VSAGetMode(&s, &a);
if (s) g_vis_enabled = 1;
}
Decode();
if ((g_samplebuf_used >= (size_t)g_framesize || (done && g_samplebuf_used > 0)) && seek_needed == -1)
{
// adjust decode position variable
if (file.isSeekReset())
last_decode_pos_ms = decode_pos_ms = 0;
else
decode_pos_ms += ((int)g_samplebuf_used / sampleFrameSize * 1000) / g_srate;
// if we have a DSP plug-in, then call it on our samples
if (mod.dsp_isactive())
{
g_samplebuf_used = mod.dsp_dosamples((short *)g_samplebuf, (int)g_samplebuf_used / sampleFrameSize, (int)g_bits, g_nch, g_srate) * sampleFrameSize;
}
Viz();
endCutter.Write((char *)g_samplebuf, (int)g_samplebuf_used);
g_samplebuf_used = 0;
needsleep = 0;
//memcpy(g_samplebuf,g_samplebuf+r,g_samplebuf_used);
}
if (done)
{
endCutter.Write(0, 0);
done = 2;
}
}
}
if (decode_pos_ms > last_decode_pos_ms + 1000)
{
last_decode_pos_ms = decode_pos_ms;
}
if (needsleep) Sleep(10);
// if we can't write data, wait a little bit. Otherwise, continue
// through the loop writing more data (without sleeping)
}
/* ---- change some globals to let everyone know we're done */
EnterCriticalSection(&g_lfnscs);
lastfn_status[0] = 0;
LeaveCriticalSection(&g_lfnscs);
g_bufferstat = 0;
g_closeaudio = 1;
/* ---- */
return 0;
}
DWORD WINAPI DecodeThread(LPVOID b)
{
DecodeLoop loop;
DWORD ret = loop.Loop();
EnterCriticalSection(&streamInfoLock);
g_playing_file = 0;
LeaveCriticalSection(&streamInfoLock);
return ret;
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef NULLSOFT_DECODETHREADH
#define NULLSOFT_DECODETHREADH
#include <windows.h>
DWORD WINAPI DecodeThread(LPVOID b);
extern volatile int seek_needed;
extern CRITICAL_SECTION g_lfnscs;
extern int g_ds;
extern int g_sndopened;
extern int g_bufferstat;
extern int g_length;
extern volatile int g_closeaudio;
extern int decode_pos_ms; // current decoding position, in milliseconds.
extern int g_vis_enabled;
#endif
+315
View File
@@ -0,0 +1,315 @@
#include "main.h"
#include "Metadata.h"
#include "../Winamp/wa_ipc.h"
#include "../nu/ns_wc.h"
#include "uvox_3901.h"
#include "uvox_3902.h"
#include "Stopper.h"
#include <shlwapi.h>
#include "../Agave/Language/api_language.h"
#include <strsafe.h>
extern CGioFile *g_playing_file;
static FILETIME ftLastWriteTime;
// is used to determine if the last write time of the file has changed when
// asked to get the metadata for the same cached file so we can update things
BOOL HasFileTimeChanged(const wchar_t *fn)
{
WIN32_FILE_ATTRIBUTE_DATA fileData = {0};
if (GetFileAttributesExW(fn, GetFileExInfoStandard, &fileData) == TRUE)
{
if(CompareFileTime(&ftLastWriteTime, &fileData.ftLastWriteTime))
{
ftLastWriteTime = fileData.ftLastWriteTime;
return TRUE;
}
}
return FALSE;
}
void UpdateFileTimeChanged(const wchar_t *fn)
{
WIN32_FILE_ATTRIBUTE_DATA fileData;
if (GetFileAttributesExW(fn, GetFileExInfoStandard, &fileData) == TRUE)
{
ftLastWriteTime = fileData.ftLastWriteTime;
}
}
Metadata *m_ext_set_mp3info = NULL;
Metadata *m_ext_get_mp3info = NULL;
extern "C" __declspec(dllexport)
int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen)
{
if (!_stricmp(data, "type"))
{
dest[0] = '0';
dest[1] = 0;
return 1;
}
if (!_stricmp(data, "rateable"))
{
dest[0] = '1';
dest[1] = 0;
return 1;
}
else if (!_stricmp(data, "family"))
{
if (!fn || !fn[0]) return 0;
int len = lstrlenW(fn);
if (len < 4 || L'.' != fn[len - 4]) return 0;
const wchar_t *p = &fn[len - 3];
if (!_wcsicmp(p, L"MP3")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MP3, dest, destlen); return 1; }
if (!_wcsicmp(p, L"MP2")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MP2, dest, destlen); return 1; }
if (!_wcsicmp(p, L"MP1")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MP1, dest, destlen); return 1; }
if (!_wcsicmp(p, L"AAC")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MPEG2_AAC, dest, destlen); return 1; }
if (!_wcsicmp(p, L"VLB")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_DOLBY, dest, destlen); return 1; }
return 0;
}
else if (!_stricmp(data, "mime"))
{
if (!fn || !fn[0]) return 0;
int len = lstrlenW(fn);
if (len < 4 || L'.' != fn[len - 4]) return 0;
const wchar_t *p = &fn[len - 3];
if (!_wcsicmp(p, L"MP3")) { StringCchCopyW(dest, destlen, L"audio/mpeg"); return 1; }
if (!_wcsicmp(p, L"MP2")) { StringCchCopyW(dest, destlen, L"audio/mpeg"); return 1; }
if (!_wcsicmp(p, L"MP1")) { StringCchCopyW(dest, destlen, L"audio/mpeg"); return 1; }
if (!_wcsicmp(p, L"AAC")) { StringCchCopyW(dest, destlen, L"audio/aac"); return 1; }
if (!_wcsicmp(p, L"VLB")) { StringCchCopyW(dest, destlen, L"audio/vlb"); return 1; }
return 0;
}
else if (!_strnicmp(data, "uvox/", 5))
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file)
{
if (g_playing_file->uvox_3901) // check again now that we've acquired the lock
{
Ultravox3901 uvox_metadata;
if (uvox_metadata.Parse(g_playing_file->uvox_3901) != API_XML_FAILURE)
{
LeaveCriticalSection(&streamInfoLock);
return uvox_metadata.GetExtendedData(data, dest, (int)destlen);
}
}
else if (g_playing_file->uvox_3902)
{
Ultravox3902 uvox_metadata;
if (uvox_metadata.Parse(g_playing_file->uvox_3902) != API_XML_FAILURE)
{
LeaveCriticalSection(&streamInfoLock);
return uvox_metadata.GetExtendedData(data, dest, (int)destlen);
}
}
}
LeaveCriticalSection(&streamInfoLock);
return 0;
}
else if (_stricmp(data, "0x3901") == 0)
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file && g_playing_file->uvox_3901) // check again now that we've acquired the lock
{
if (dest == NULL) // It's empty, he's looking for the size of the 0x3901
{
int size = MultiByteToWideChar(CP_UTF8, 0, g_playing_file->uvox_3901, -1, 0, 0);
LeaveCriticalSection(&streamInfoLock);
return size;
}
else
{
MultiByteToWideCharSZ(CP_UTF8, 0, g_playing_file->uvox_3901, -1, dest, (int)destlen);
LeaveCriticalSection(&streamInfoLock);
return 1;
}
}
LeaveCriticalSection(&streamInfoLock);
return 0;
}
else if (!_stricmp(data, "streamtype"))
{
if (lstrcmpW(lastfn, fn))
return 0;
if (g_playing_file)
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file) // check again now that we've acquired the lock
{
StringCchPrintfW(dest, destlen, L"%d", g_playing_file->IsStream());
LeaveCriticalSection(&streamInfoLock);
return 1;
}
LeaveCriticalSection(&streamInfoLock);
}
return 0;
}
else if (!_stricmp(data, "streammetadata"))
{
if (lstrcmpW(lastfn, fn))
return 0;
if (g_playing_file)
{
uint32_t len=0;
EnterCriticalSection(&streamInfoLock);
if (g_playing_file && g_playing_file->GetID3v2(&len) && len > 0) // check again now that we've acquired the lock
{
lstrcpynW(dest, L"1", (int)destlen);
LeaveCriticalSection(&streamInfoLock);
return 1; // always return 1 to ensure we can do title lookups
}
LeaveCriticalSection(&streamInfoLock);
}
return 0;
}
else if (!_stricmp(data, "streamtitle"))
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file) // check again now that we've acquired the lock
ConvertTryUTF8(g_playing_file->stream_current_title, dest, destlen);
else
dest[0]=0;
LeaveCriticalSection(&streamInfoLock);
return 1;
}
else if (!_stricmp(data, "streamname"))
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file) // check again now that we've acquired the lock
ConvertTryUTF8(g_playing_file->stream_name, dest, destlen);
else
dest[0]=0;
LeaveCriticalSection(&streamInfoLock);
return 1;
}
else if (!_stricmp(data, "streamurl"))
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file) // check again now that we've acquired the lock
ConvertTryUTF8(g_playing_file->stream_url, dest, destlen);
else
dest[0]=0;
LeaveCriticalSection(&streamInfoLock);
return 1;
}
else if (!_stricmp(data, "streamgenre"))
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file) // check again now that we've acquired the lock
ConvertTryUTF8(g_playing_file->stream_genre, dest, destlen);
else
dest[0]=0;
LeaveCriticalSection(&streamInfoLock);
return 1;
}
else if (!_stricmp(data, "streaminformation"))
{
EnterCriticalSection(&streamInfoLock);
if (g_playing_file)
g_playing_file->GetStreamInfo(dest, destlen);
else
dest[0]=0;
LeaveCriticalSection(&streamInfoLock);
return 1;
}
if (!fn || !fn[0]) return 0;
if (!_wcsnicmp(fn, L"uvox://", 7))
return 0;
if (g_playing_file && PathIsURL(fn) && !lstrcmpW(lastfn, fn))
{
EnterCriticalSection(&streamInfoLock);
uint32_t len = 0;
if (g_playing_file && g_playing_file->GetID3v2(&len) && len > 0) // check again now that we've acquired the lock
{
Metadata meta(g_playing_file, fn);
int ret = meta.GetExtendedData(data, dest, (int)destlen);
LeaveCriticalSection(&streamInfoLock);
return ret;
}
LeaveCriticalSection(&streamInfoLock);
}
if (PathIsURL(fn))
return 0;
if (m_ext_get_mp3info && (!m_ext_get_mp3info->IsMe(fn) || HasFileTimeChanged(fn)))
{
m_ext_get_mp3info->Release();
m_ext_get_mp3info=0;
}
if (!m_ext_get_mp3info)
{
m_ext_get_mp3info = new Metadata;
m_ext_get_mp3info->Open(fn);
}
return m_ext_get_mp3info->GetExtendedData(data, dest, (int)destlen);
}
extern "C"
__declspec(dllexport) int winampSetExtendedFileInfoW(const wchar_t *fn, const char *data, const wchar_t *val)
{
if (!m_ext_set_mp3info || (m_ext_set_mp3info && !m_ext_set_mp3info->IsMe(fn)))
{
if(m_ext_set_mp3info) m_ext_set_mp3info->Release();
m_ext_set_mp3info = new Metadata;
m_ext_set_mp3info->Open(fn);
}
return m_ext_set_mp3info->SetExtendedData(data, val);
}
extern "C"
__declspec(dllexport) int winampWriteExtendedFileInfo()
{
// flush our read cache too :)
if(m_ext_get_mp3info) m_ext_get_mp3info->Release();
m_ext_get_mp3info = NULL;
if (!m_ext_set_mp3info) return 0;
Stopper stopper;
if (m_ext_set_mp3info->IsMe(lastfn))
stopper.Stop();
// just in-case something changed
if (!m_ext_set_mp3info) return 0;
int ret = m_ext_set_mp3info->Save();
stopper.Play();
m_ext_set_mp3info->Release();
m_ext_set_mp3info = NULL;
// update last modified so we're not re-queried on our own updates
UpdateFileTimeChanged(lastfn);
return !ret;
}
extern "C" __declspec(dllexport)
int winampClearExtendedFileInfoW(const wchar_t *fn)
{
Metadata meta;
if (meta.Open(fn)==METADATA_SUCCESS)
{
meta.id3v2.Clear();
Stopper stopper;
if (meta.IsMe(lastfn))
stopper.Stop();
meta.Save();
stopper.Play();
// update last modified so we're not re-queried on our own updates
UpdateFileTimeChanged(fn);
return 1;
}
return 0;
}
+323
View File
@@ -0,0 +1,323 @@
#include "main.h"
#include "adts.h"
#include <memory.h>
#include <malloc.h>
#include <xutility>
#include <assert.h>
#include <shlwapi.h>
#include <foundation/error.h>
#include "../nu/RingBuffer.h"
#include <api/service/waservicefactory.h>
// {19450308-90D7-4E45-8A9D-DC71E67123E2}
static const GUID adts_aac_guid =
{ 0x19450308, 0x90d7, 0x4e45, { 0x8a, 0x9d, 0xdc, 0x71, 0xe6, 0x71, 0x23, 0xe2 } };
// {4192FE3F-E843-445c-8D62-51BE5EE5E68C}
static const GUID adts_mp2_guid =
{ 0x4192fe3f, 0xe843, 0x445c, { 0x8d, 0x62, 0x51, 0xbe, 0x5e, 0xe5, 0xe6, 0x8c } };
class GapCutter
{
public:
GapCutter() {}
void SetEndSize( int postSize );
void SetSize( int preSize, int postSize );
void Flush( int time_in_ms );
int Write( void *dest, void *input, size_t inputBytes );
private:
RingBuffer ringBuffer;
int preCut = 0;
int preCutSize = 0;
};
void GapCutter::SetEndSize(int postSize)
{
if (postSize < 0)
postSize = 0;
if (postSize)
{
ringBuffer.Reset();
ringBuffer.reserve(postSize);
}
}
void GapCutter::SetSize( int preSize, int postSize )
{
if ( preSize < 0 )
preSize = 0;
if ( postSize < 0 )
postSize = 0;
SetEndSize( postSize );
preCutSize = preSize;
preCut = preSize;
}
void GapCutter::Flush( int time_in_ms )
{
// if (time_in_ms == 0) // TODO: calculate actual delay if we seek within the encoder delay area
preCut = preCutSize; // reset precut size if we seek to the start
ringBuffer.clear();
}
int GapCutter::Write( void *dest, void *input, size_t inputBytes ) // returns # of bytes written
{
int bytesWritten = 0;
unsigned __int8 *in = (unsigned __int8 *)input;
unsigned __int8 *out = (unsigned __int8 *)dest;
// cut pre samples, if necessary
intptr_t pre = min( preCut, (intptr_t)inputBytes );
in += pre;
inputBytes -= pre;
preCut -= (int)pre;
if ( !inputBytes )
return bytesWritten;
size_t remainingFill = ringBuffer.avail();
intptr_t fillWrite = min( (intptr_t)( inputBytes - remainingFill ), (intptr_t)ringBuffer.size() ); // only write fill buffer if we've got enough left to fill it up
if ( fillWrite > 0 )
{
size_t written = ringBuffer.read( out, fillWrite );
bytesWritten += (int)written;
out += written;
}
remainingFill = ringBuffer.avail();
int outWrite = (int)max( 0, (intptr_t)( inputBytes - remainingFill ) );
if ( outWrite )
memcpy( out, in, outWrite );
bytesWritten += outWrite;
in += outWrite;
inputBytes -= outWrite;
if ( inputBytes )
ringBuffer.write( in, inputBytes );
return bytesWritten;
}
struct ExtendedRead
{
ExtendedRead() { memset(&data, 0, sizeof(data)); }
~ExtendedRead()
{
file.Close();
if ( decoder )
{
decoder->Close();
decoder->Release();
}
}
bool Open( const wchar_t *fn, int *size, int *bps, int *nch, int *srate, bool useFloat );
adts *decoder = NULL;
int bits = 0;
size_t initialData = 0;
int frameSize = 0;
GapCutter cutter;
CGioFile file;
#define DATA_SIZE (6*4*2*2*1152)
unsigned char data[DATA_SIZE];
};
bool ExtendedRead::Open(const wchar_t *fn, int *size, int *bps, int *nch, int *srate, bool useFloat)
{
if (file.Open(fn, config_max_bufsize_k) != NErr_Success)
return false;
int downmix = 0;
bool allowsurround = 1;
if (*nch == 1)
{
downmix = 1;
allowsurround = 0;
}
else if (*nch == 2)
{
allowsurround = 0;
}
if (useFloat)
bits=32;
else if (*bps == 24)
bits = 24;
else
{
bits = 16;
*bps = 16;
}
wchar_t *ext = PathFindExtensionW(fn);
if (!_wcsicmp(ext, L".vlb"))
{
return false;
}
else if (!_wcsicmp(ext, L".aac") || !_wcsicmp(ext, L".apl"))
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(adts_aac_guid);
if (factory)
decoder = (adts *)factory->getInterface();
}
else
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(adts_mp2_guid);
if (factory)
decoder = (adts *)factory->getInterface();
}
if (!decoder)
return false;
decoder->Initialize(!!downmix, 0, allowsurround, bits, false, useFloat);
decoder->Open(&file);
size_t bitrate;
bool done=false;
while (!done)
{
switch (decoder->Sync(&file, data, sizeof(data), &initialData, &bitrate))
{
case adts::SUCCESS:
done=true;
break;
case adts::FAILURE:
case adts::ENDOFFILE:
return false;
case adts::NEEDMOREDATA:
break;
}
}
size_t numBits = 0;
decoder->GetOutputParameters(&numBits, nch, srate);
*bps = bits = (int)numBits;
frameSize = bits / 8 * *nch;
if (config_gapless)
cutter.SetSize((file.prepad + (int)decoder->GetDecoderDelay())*frameSize, (file.postpad - (int)decoder->GetDecoderDelay())*frameSize);
if (file.m_vbr_samples) // exact number of samples in the LAME header, how nice :)
*size = (int)file.m_vbr_samples*frameSize;
else if (file.m_vbr_ms) // if we know the milliseconds accurately
*size = MulDiv(*srate * frameSize, file.m_vbr_ms, 1000); // our size should be mostly accurate
else // no helpful info to go on
{
// just guess based on bitrate and content length
bitrate=decoder->GetCurrentBitrate();
int len_ms = MulDiv(file.GetContentLength(), 8, (int)bitrate);
*size = MulDiv(*srate * frameSize, len_ms, 1000);
}
return true;
}
extern "C"
{
//returns handle!=0 if successful, 0 if error
//size will return the final nb of bytes written to the output, -1 if unknown
__declspec(dllexport) intptr_t winampGetExtendedRead_openW(const wchar_t *fn, int *size, int *bps, int *nch, int *srate)
{
ExtendedRead *ext = new ExtendedRead;
if (ext)
{
if (ext->Open(fn, size, bps, nch, srate, false))
return reinterpret_cast<intptr_t>(ext);
delete ext;
}
return 0;
}
__declspec(dllexport) intptr_t winampGetExtendedRead_openW_float(const wchar_t *fn, int *size, int *bps, int *nch, int *srate)
{
ExtendedRead *ext = new ExtendedRead;
if (ext)
{
if (ext->Open(fn, size, bps, nch, srate, true))
return reinterpret_cast<intptr_t>(ext);
delete ext;
}
return 0;
}
//returns nb of bytes read. -1 if read error (like CD ejected). if (ret==0), EOF is assumed
__declspec(dllexport) size_t winampGetExtendedRead_getData(intptr_t handle, char *dest, size_t len, int *killswitch)
{
ExtendedRead *ext = (ExtendedRead *)handle;
int copied = 0;
if (ext)
{
len -= (len % ext->frameSize); // only do whole frames
while (len)
{
size_t toMove = min(len, ext->initialData);
int toCopy = ext->cutter.Write(dest, ext->data, toMove);
if (ext->initialData != toMove)
memmove(ext->data, ext->data + toMove, ext->initialData - toMove);
ext->initialData -= toMove;
len -= toCopy;
copied += toCopy;
dest += toCopy;
if (!ext->initialData)
{
size_t written = 0, bitrate, endCut = 0;
int ret = ext->decoder->Decode(&ext->file, ext->data, DATA_SIZE, &written, &bitrate, &endCut);
if (config_gapless && endCut)
ext->cutter.SetEndSize((int)(endCut - ext->decoder->GetDecoderDelay())*ext->frameSize);
ext->initialData = written;
if (/*ret != adts::SUCCESS && */!ext->initialData && (copied || ret == adts::ENDOFFILE))
return copied;
if (ret == adts::FAILURE)
return -1;
}
}
}
return copied;
}
// return nonzero on success, zero on failure.
__declspec(dllexport) int winampGetExtendedRead_setTime(intptr_t handle, int millisecs)
{
ExtendedRead *ext = (ExtendedRead *)handle;
if (ext)
{
if (!ext->file.IsSeekable()) return 0; // not seekable
int br = ext->file.GetAvgVBRBitrate();
if (!br) br = (int)ext->decoder->GetCurrentBitrate();
if (!br) return 0; // can't find a valid bitrate
ext->cutter.Flush(millisecs); // fucko?
ext->decoder->Flush(&ext->file);
ext->file.Seek(millisecs,br);
return 1;
}
return 0;
}
__declspec(dllexport) void winampGetExtendedRead_close(intptr_t handle)
{
ExtendedRead *ext = (ExtendedRead *)handle;
if (ext) delete ext;
}
}
+25
View File
@@ -0,0 +1,25 @@
#include "api__in_mp3.h"
#include <api/service/waservicefactory.h>
template <class api_T>
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
{
if (mod.service)
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
api_t = reinterpret_cast<api_T *>( factory->getInterface() );
}
}
template <class api_T>
void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
{
if (mod.service && api_t)
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
factory->releaseInterface(api_t);
}
api_t = NULL;
}
+10
View File
@@ -0,0 +1,10 @@
#include "main.h"
#include "MP3Info.h"
#include "../nu/AutoWide.h"
#include "id3.h"
#include "api.h"
#include <math.h>
#include "config.h"
#include "LAMEinfo.h"
#include <strsafe.h>
+211
View File
@@ -0,0 +1,211 @@
#include "ID3v1.h"
#include "../nu/ns_wc.h"
#include <windows.h>
#include "config.h"
#include <strsafe.h>
const wchar_t *id3v1_genres[] =
{
L"Blues", L"Classic Rock", L"Country", L"Dance", L"Disco", L"Funk", L"Grunge",
L"Hip-Hop", L"Jazz", L"Metal", L"New Age", L"Oldies", L"Other", L"Pop", L"R&B",
L"Rap", L"Reggae", L"Rock", L"Techno", L"Industrial", L"Alternative", L"Ska",
L"Death Metal", L"Pranks", L"Soundtrack", L"Euro-Techno", L"Ambient", L"Trip-Hop",
L"Vocal", L"Jazz+Funk", L"Fusion", L"Trance", L"Classical", L"Instrumental",
L"Acid", L"House", L"Game", L"Sound Clip", L"Gospel", L"Noise", L"Alt Rock",
L"Bass", L"Soul", L"Punk", L"Space", L"Meditative", L"Instrumental Pop",
L"Instrumental Rock", L"Ethnic", L"Gothic", L"Darkwave", L"Techno-Industrial",
L"Electronic", L"Pop-Folk", L"Eurodance", L"Dream", L"Southern Rock", L"Comedy",
L"Cult", L"Gangsta Rap", L"Top 40", L"Christian Rap", L"Pop/Funk", L"Jungle",
L"Native American", L"Cabaret", L"New Wave", L"Psychedelic", L"Rave", L"Showtunes",
L"Trailer", L"Lo-Fi", L"Tribal", L"Acid Punk", L"Acid Jazz", L"Polka", L"Retro",
L"Musical", L"Rock & Roll", L"Hard Rock", L"Folk", L"Folk-Rock", L"National Folk",
L"Swing", L"Fast-Fusion", L"Bebop", L"Latin", L"Revival", L"Celtic", L"Bluegrass",
L"Avantgarde", L"Gothic Rock", L"Progressive Rock", L"Psychedelic Rock",
L"Symphonic Rock", L"Slow Rock", L"Big Band", L"Chorus", L"Easy Listening",
L"Acoustic", L"Humour", L"Speech", L"Chanson", L"Opera", L"Chamber Music", L"Sonata",
L"Symphony", L"Booty Bass", L"Primus", L"Porn Groove", L"Satire", L"Slow Jam",
L"Club", L"Tango", L"Samba", L"Folklore", L"Ballad", L"Power Ballad", L"Rhythmic Soul",
L"Freestyle", L"Duet", L"Punk Rock", L"Drum Solo", L"A Cappella", L"Euro-House",
L"Dance Hall", L"Goa", L"Drum & Bass", L"Club-House", L"Hardcore", L"Terror", L"Indie",
L"BritPop", L"Afro-Punk", L"Polsk Punk", L"Beat", L"Christian Gangsta Rap",
L"Heavy Metal", L"Black Metal", L"Crossover", L"Contemporary Christian",
L"Christian Rock", L"Merengue", L"Salsa", L"Thrash Metal", L"Anime", L"JPop",
L"Synthpop", L"Abstract", L"Art Rock", L"Baroque", L"Bhangra", L"Big Beat",
L"Breakbeat", L"Chillout", L"Downtempo", L"Dub", L"EBM", L"Eclectic", L"Electro",
L"Electroclash", L"Emo", L"Experimental", L"Garage", L"Global", L"IDM", L"Illbient",
L"Industro-Goth", L"Jam Band", L"Krautrock", L"Leftfield", L"Lounge", L"Math Rock",
L"New Romantic", L"Nu-Breakz", L"Post-Punk", L"Post-Rock", L"Psytrance", L"Shoegaze",
L"Space Rock", L"Trop Rock", L"World Music", L"Neoclassical", L"Audiobook",
L"Audio Theatre", L"Neue Deutsche Welle", L"Podcast", L"Indie Rock", L"G-Funk",
L"Dubstep", L"Garage Rock", L"Psybient", L"Glam Rock", L"Dream Pop", L"Merseybeat",
L"K-Pop", L"Chiptune", L"Grime", L"Grindcore", L"Indietronic", L"Indietronica",
L"Jazz Rock", L"Jazz Fusion", L"Post-Punk Revival", L"Electronica", L"Psychill",
L"Ethnotronic", L"Americana", L"Ambient Dub", L"Digital Dub", L"Chillwave", L"Stoner Rock",
L"Slowcore", L"Softcore", L"Flamenco", L"Hi-NRG", L"Ethereal", L"Drone", L"Doom Metal",
L"Doom Jazz", L"Mainstream", L"Glitch", L"Balearic", L"Modern Classical", L"Mod",
L"Contemporary Classical", L"Psybreaks", L"Psystep", L"Psydub", L"Chillstep", L"Berlin School",
L"Future Jazz", L"Djent", L"Musique Concrète", L"Electroacoustic", L"Folktronica", L"Texas Country", L"Red Dirt",
L"Arabic", L"Asian", L"Bachata", L"Bollywood", L"Cajun", L"Calypso", L"Creole", L"Darkstep", L"Jewish", L"Reggaeton", L"Smooth Jazz",
L"Soca", L"Spiritual", L"Turntablism", L"Zouk", L"Neofolk", L"Nu Jazz",
};
size_t numGenres = sizeof(id3v1_genres)/sizeof(*id3v1_genres);
ID3v1::ID3v1()
{
title[0]=0;
artist[0]=0;
album[0]=0;
comment[0]=0;
year[0]=0;
genre=255;
track=0;
hasData=false;
dirty=false;
title[30]=0;
artist[30]=0;
album[30]=0;
comment[30]=0;
year[4]=0;
}
int ID3v1::Decode(const void *data)
{
const char *fbuf = (const char *)data;
ptrdiff_t x;
hasData = false;
title[0] = artist[0] = album[0] = year[0] = comment[0] = 0;
genre = 255; track = 0;
if (memcmp(fbuf, "TAG", 3))
{
return 1;
}
memcpy(title, fbuf + 3, 30); x = 29; while (x >= 0 && title[x] == ' ') x--; title[x + 1] = 0;
memcpy(artist, fbuf + 33, 30); x = 29; while (x >= 0 && artist[x] == ' ') x--; artist[x + 1] = 0;
memcpy(album, fbuf + 63, 30); x = 29; while (x >= 0 && album[x] == ' ') x--; album[x + 1] = 0;
memcpy(year, fbuf + 93, 4); x = 3; while (x >= 0 && year[x] == ' ') x--; year[x + 1] = 0;
memcpy(comment, fbuf + 97, 30); x = 29; while (x >= 0 && comment[x] == ' ') x--; comment[x + 1] = 0;
if (fbuf[97 + 28] == 0 && fbuf[97 + 28 + 1] != 0) track = fbuf[97 + 28 + 1];
genre = ((unsigned char *)fbuf)[127];
hasData = 1;
return 0;
}
int ID3v1::Encode(void *data)
{
if (!hasData)
return 1;
char *fbuf = (char *)data;
size_t x;
fbuf[0] = 'T';fbuf[1] = 'A';fbuf[2] = 'G';
if (title) strncpy(fbuf + 3, title, 30); for (x = 3 + strlen(title); x < 33; x ++) fbuf[x] = 0;
if (artist) strncpy(fbuf + 33, artist, 30); for (x = 33 + strlen(artist); x < 63; x ++) fbuf[x] = 0;
if (album) strncpy(fbuf + 63, album, 30); for (x = 63 + strlen(album); x < 93; x ++) fbuf[x] = 0;
if (year) strncpy(fbuf + 93, year, 4); for (x = 93 + strlen(year); x < 97; x ++) fbuf[x] = 0;
if (comment) strncpy(fbuf + 97, comment, 30); for (x = 97 + strlen(comment); x < 127; x ++) fbuf[x] = 0;
if (track)
{
fbuf[97 + 28] = 0;
fbuf[97 + 28 + 1] = track;
}
((unsigned char *)fbuf)[127] = genre;
return 0;
}
#define ID3V1_CODEPAGE ((config_read_mode==READ_LOCAL)?CP_ACP:28591)
int ID3v1::GetString(const char *tag, wchar_t *data, int dataLen)
{
if (!hasData)
return 0;
if (!_stricmp(tag, "title"))
{
MultiByteToWideCharSZ(ID3V1_CODEPAGE, 0, title, -1, data, dataLen);
return 1;
}
else if (!_stricmp(tag, "artist"))
{
MultiByteToWideCharSZ(ID3V1_CODEPAGE, 0, artist, -1, data, dataLen);
return 1;
}
else if (!_stricmp(tag, "album"))
{
MultiByteToWideCharSZ(ID3V1_CODEPAGE, 0, album, -1, data, dataLen);
return 1;
}
else if (!_stricmp(tag, "comment"))
{
MultiByteToWideCharSZ(ID3V1_CODEPAGE, 0, comment, -1, data, dataLen);
return 1;
}
else if (!_stricmp(tag, "year"))
{
MultiByteToWideCharSZ(ID3V1_CODEPAGE, 0, year, -1, data, dataLen);
return 1;
}
else if (!_stricmp(tag, "genre"))
{
if (genre >= numGenres) return -1;
StringCchCopyW(data, dataLen, id3v1_genres[genre]);
return 1;
}
else if (!_stricmp(tag, "track"))
{
if (track == 0) return -1;
StringCchPrintfW(data, dataLen, L"%u", track);
return 1;
}
else
return 0;
}
int ID3v1::SetString(const char *tag, const wchar_t *data)
{
if (!_stricmp(tag, "title"))
WideCharToMultiByteSZ(ID3V1_CODEPAGE, 0, data, -1, title, 31, 0 ,0);
else if (!_stricmp(tag, "artist"))
WideCharToMultiByteSZ(ID3V1_CODEPAGE, 0, data, -1, artist, 31, 0 ,0);
else if (!_stricmp(tag, "album"))
WideCharToMultiByteSZ(ID3V1_CODEPAGE, 0, data, -1, album, 31, 0 ,0);
else if (!_stricmp(tag, "comment"))
WideCharToMultiByteSZ(ID3V1_CODEPAGE, 0, data, -1, comment, 31, 0 ,0);
else if (!_stricmp(tag, "year"))
WideCharToMultiByteSZ(ID3V1_CODEPAGE, 0, data, -1, year, 5, 0 ,0);
else if (!_stricmp(tag, "genre"))
{
genre=255;
if (data)
{
for (size_t i=0;i<numGenres;i++)
{
if (!_wcsicmp(id3v1_genres[i], data))
{
genre= (unsigned char)i;
}
}
}
}
else if (!_stricmp(tag, "track"))
{
int t = _wtoi(data);
if(t > 255) track = 0;
else track = t;
}
else
return 0;
dirty=true;
hasData = 1;
return 1;
}
void ID3v1::Clear()
{
hasData=false;
dirty=true;
//clear data
title[0]=artist[0]=album[0]=comment[0]=year[0]=0;
genre = track = 0;
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef NULLSOFT_IN_MP3_ID3V1_H
#define NULLSOFT_IN_MP3_ID3V1_H
#include <bfc/platform/types.h>
class ID3v1
{
public:
ID3v1();
int Decode(const void *data);
// return -1 for empty, 1 for OK, 0 for "don't understand tag name"
int GetString(const char *tag, wchar_t *data, int dataLen);
// returns 1 for OK, 0 for "don't understand tag name"
int SetString(const char *tag, const wchar_t *data);
int Encode(void *data);
bool IsDirty() { return dirty; }
bool HasData() { return hasData; }
void Clear();
private:
char title[31],artist[31],album[31],comment[31];
char year[5];
unsigned char genre;
unsigned char track;
bool hasData;
bool dirty;
};
#endif
+654
View File
@@ -0,0 +1,654 @@
#include "ID3v2.h"
#include "id3.h"
#include "config.h"
#include "api__in_mp3.h"
#include "../Agave/AlbumArt/svc_albumArtProvider.h"
#include "../nu/AutoChar.h"
#include "../nu/AutoWide.h"
#include <strsafe.h>
static inline const wchar_t *IncSafe(const wchar_t *val, int x)
{
while (x--)
{
if (val && *val)
val++;
}
return val;
}
extern const wchar_t *id3v1_genres[];
extern size_t numGenres;
ID3v2::ID3v2()
{
hasData=false;
dirty=false;
}
int ID3v2::Decode(const void *data, size_t len)
{
if (!config_parse_id3v2 || !data)
{
hasData=false;
return 0;
}
id3v2.Parse((uchar *)data, (uchar *)data+ID3_TAGHEADERSIZE);
if (id3v2.NumFrames() > 0)
{
hasData=true;
return 0;
}
else
return 1;
}
// return -1 for empty, 1 for OK, 0 for "don't understand tag name"
int ID3v2::GetString(const char *tag, wchar_t *data, int dataLen)
{
if (!_stricmp(tag, "title"))
return ID3_GetTagText(&id3v2, ID3FID_TITLE, data, dataLen)?1:-1;
else if (!_stricmp(tag, "album"))
return ID3_GetTagText(&id3v2, ID3FID_ALBUM, data, dataLen)?1:-1;
else if (!_stricmp(tag, "artist"))
return ID3_GetTagText(&id3v2, ID3FID_LEADARTIST, data, dataLen)?1:-1;
else if (!_stricmp(tag, "albumartist"))
{
if (!ID3_GetTagText(&id3v2, ID3FID_BAND, data, dataLen) && !ID3_GetUserText(&id3v2, L"ALBUM ARTIST", data, dataLen) && !ID3_GetUserText(&id3v2, L"ALBUMARTIST", data, dataLen))
return ID3_GetUserText(&id3v2, L"Band", data, dataLen)?1:-1;
else
return 1;
}
else if (!_stricmp(tag, "comment"))
return ID3_GetComment(&id3v2, data, dataLen)?1:-1;
else if (!_stricmp(tag, "year"))
{
if (!ID3_GetTagText(&id3v2, ID3FID_RECORDINGTIME, data, dataLen))
return ID3_GetTagText(&id3v2, ID3FID_YEAR, data, dataLen)?1:-1;
else
return 1;
}
else if (!_stricmp(tag, "composer"))
return ID3_GetTagText(&id3v2, ID3FID_COMPOSER, data, dataLen)?1:-1;
else if (!_stricmp(tag, "replaygain_track_gain"))
return ID3_GetUserText(&id3v2, L"replaygain_track_gain", data, dataLen)?1:-1;
else if (!_stricmp(tag, "replaygain_album_gain"))
return ID3_GetUserText(&id3v2, L"replaygain_album_gain", data, dataLen)?1:-1;
else if (!_stricmp(tag, "replaygain_track_peak"))
return ID3_GetUserText(&id3v2, L"replaygain_track_peak", data, dataLen)?1:-1;
else if (!_stricmp(tag, "replaygain_album_peak"))
return ID3_GetUserText(&id3v2, L"replaygain_album_peak", data, dataLen)?1:-1;
else if (!_stricmp(tag, "genre"))
{
data[0] = 0;
if (ID3_GetTagText(&id3v2, ID3FID_CONTENTTYPE, data, dataLen))
{
wchar_t *tmp = data;
while (tmp && *tmp == ' ') tmp++;
if (tmp && (*tmp == '(' || (*tmp >= '0' && *tmp <= '9'))) // both (%d) and %d forms
{
int noparam = 0;
if (*tmp == '(') tmp++;
else noparam = 1;
size_t genre_index = _wtoi(tmp);
int cnt = 0;
while (tmp && *tmp >= '0' && *tmp <= '9') cnt++, tmp++;
while (tmp && *tmp == ' ') tmp++;
if (tmp && (((!*tmp && noparam) || (!noparam && *tmp == ')')) && cnt > 0))
{
if (genre_index < numGenres)
StringCchCopyW(data, dataLen, id3v1_genres[genre_index]);
}
}
return 1;
}
return -1;
}
else if (!_stricmp(tag, "track"))
return ID3_GetTagText(&id3v2, ID3FID_TRACKNUM, data, dataLen)?1:-1;
else if (!_stricmp(tag, "disc"))
return ID3_GetTagText(&id3v2, ID3FID_PARTINSET, data, dataLen)?1:-1;
else if (!_stricmp(tag, "bpm"))
return ID3_GetTagText(&id3v2, ID3FID_BPM, data, dataLen)?1:-1;
else if (!_stricmp(tag, "rating"))
return ID3_GetRating(&id3v2, data, dataLen)?1:-1;
else if (!_stricmp(tag, "conductor"))
return ID3_GetTagText(&id3v2, ID3FID_CONDUCTOR, data, dataLen)?1:-1;
else if (!_stricmp(tag, "key"))
return ID3_GetTagText(&id3v2, ID3FID_KEY, data, dataLen)?1:-1;
else if (!_stricmp(tag, "mood"))
return ID3_GetTagText(&id3v2, ID3FID_MOOD, data, dataLen)?1:-1;
else if (!_stricmp(tag, "subtitle"))
return ID3_GetTagText(&id3v2, ID3FID_SUBTITLE, data, dataLen)?1:-1;
else if (!_stricmp(tag, "lyricist"))
return ID3_GetTagText(&id3v2, ID3FID_LYRICIST, data, dataLen)?1:-1;
else if (!_stricmp(tag, "ISRC"))
return ID3_GetTagText(&id3v2, ID3FID_ISRC, data, dataLen)?1:-1;
else if (!_stricmp(tag, "media"))
return ID3_GetTagText(&id3v2, ID3FID_MEDIATYPE, data, dataLen)?1:-1;
else if (!_stricmp(tag, "remixing"))
return ID3_GetTagText(&id3v2, ID3FID_MIXARTIST, data, dataLen)?1:-1;
else if (!_stricmp(tag, "originalartist"))
return ID3_GetTagText(&id3v2, ID3FID_ORIGARTIST, data, dataLen)?1:-1;
else if (!_stricmp(tag, "encoder"))
return ID3_GetTagText(&id3v2, ID3FID_ENCODERSETTINGS, data, dataLen)?1:-1;
else if (!_stricmp(tag, "publisher"))
return ID3_GetTagText(&id3v2, ID3FID_PUBLISHER, data, dataLen)?1:-1;
else if (!_stricmp(tag, "copyright"))
return ID3_GetTagText(&id3v2, ID3FID_COPYRIGHT, data, dataLen)?1:-1;
else if (!_stricmp(tag, "compilation"))
return ID3_GetTagText(&id3v2, ID3FID_COMPILATION, data, dataLen)?1:-1;
else if (!_stricmp(tag, "url"))
return ID3_GetTagUrl(&id3v2, ID3FID_WWWUSER, data, dataLen)?1:-1;
else if (!_stricmp(tag, "GracenoteFileID"))
return ID3_GetGracenoteTagID(&id3v2, data, dataLen)?1:-1;
else if (!_stricmp(tag, "GracenoteExtData"))
{
if (!ID3_GetUserText(&id3v2, L"GN_ExtData", data, dataLen))
return ID3_GetUserText(&id3v2, L"GN/ExtData", data, dataLen)?1:-1;
else
return 1;
}
else if (!_stricmp(tag, "tool"))
return ID3_GetTagText(&id3v2, ID3FID_ENCODEDBY, data, dataLen)?1:-1;
else if (!_stricmp(tag, "pregap"))
{
data[0] = 0;
// first, check for stupid iTunSMPB TXXX frame
wchar_t gaps[128] = L"";
const wchar_t *itr = ID3_GetComment(&id3v2, L"iTunSMPB", gaps, 128);
if (itr && *itr)
{
itr = IncSafe(itr, 9);
unsigned int prepad = wcstoul(itr, 0, 16);
StringCchPrintfW(data, dataLen, L"%u", prepad);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "postgap"))
{
data[0] = 0;
// first, check for stupid iTunSMPB TXXX frame
wchar_t gaps[128] = L"";
const wchar_t *itr = ID3_GetComment(&id3v2, L"iTunSMPB", gaps, 128);
if (itr && *itr)
{
itr = IncSafe(itr, 18);
unsigned int postpad = wcstoul(itr, 0, 16);
StringCchPrintfW(data, dataLen, L"%u", postpad);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "numsamples"))
{
data[0] = 0;
// first, check for stupid iTunSMPB TXXX frame
wchar_t gaps[128] = L"";
const wchar_t *itr = ID3_GetComment(&id3v2, L"iTunSMPB", gaps, 128);
if (itr && *itr)
{
itr = IncSafe(itr, 27);
unsigned __int64 samples = wcstoul(itr, 0, 16);
StringCchPrintfW(data, dataLen, L"%I64u", samples);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "endoffset"))
{
data[0] = 0;
// first, check for stupid iTunSMPB TXXX frame
wchar_t gaps[128] = L"";
const wchar_t *itr = ID3_GetComment(&id3v2, L"iTunSMPB", gaps, 128);
if (itr && *itr)
{
itr = IncSafe(itr, 53);
unsigned __int32 endoffset = wcstoul(itr, 0, 16);
StringCchPrintfW(data, dataLen, L"%I32u", endoffset);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "category"))
{
return ID3_GetTagText(&id3v2, ID3FID_CONTENTGROUP, data, dataLen)?1:-1;
}
// things generally added by Musicbrainz tagging (either specific or additional)
else if (!_stricmp(tag, "acoustid") || !_stricmp(tag, "acoustid_id"))
{
return ID3_GetUserText(&id3v2, L"Acoustid Id", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "acoustid_fingerprint"))
{
return ID3_GetUserText(&id3v2, L"Acoustid Fingerprint", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "asin"))
{
return ID3_GetUserText(&id3v2, L"ASIN", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "barcode"))
{
return ID3_GetUserText(&id3v2, L"BARCODE", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "catalognumber"))
{
return ID3_GetUserText(&id3v2, L"CATALOGNUMBER", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "script"))
{
return ID3_GetUserText(&id3v2, L"SCRIPT", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_recordingid")) // (track id)
{
return ID3_GetMusicbrainzRecordingID(&id3v2, data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_trackid")) // TODO not working (album track id)
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Release Track Id", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_albumid"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Album Id", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_artistid"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Artist Id", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_albumartistid"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Album Artist Id", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_releasestatus") || !_stricmp(tag, "musicbrainz_albumstatus"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Album Status", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_releasetype") || !_stricmp(tag, "musicbrainz_albumtype"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Album Type", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_releasecountry") || !_stricmp(tag, "musicbrainz_albumcountry"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Album Release Country", data, dataLen)?1:-1;
}
else if (!_stricmp(tag, "musicbrainz_releasegroupid") || !_stricmp(tag, "musicbrainz_albumgroupid"))
{
return ID3_GetUserText(&id3v2, L"MusicBrainz Release Group Id", data, dataLen)?1:-1;
}
else
{
return 0;
}
}
void ID3v2::add_set_latin_id3v2_frame(ID3_FrameID id, const wchar_t *c)
{
ID3_Frame *f = id3v2.Find(id);
if (!c)
{
if (f)
id3v2.RemoveFrame(f);
}
else
{
if (f)
{
SetFrameEncoding(f, ENCODING_FORCE_ASCII);
AutoChar temp(c); //AutoChar temp(c, 28591); // todo: benski> changed back to local to keep old winamp tagged files working
f->Field(ID3FN_URL).SetLocal(temp); //f->Field(ID3FN_TEXT).SetLatin(temp);// todo: benski> changed back to local to keep old winamp tagged files working
}
else
{
f = new ID3_Frame(id);
SetFrameEncoding(f, ENCODING_FORCE_ASCII);
AutoChar temp(c); //AutoChar temp(c, 28591); // todo: benski> changed back to local to keep old winamp tagged files working
f->Field(ID3FN_URL).SetLocal(temp); //f->Field(ID3FN_TEXT).SetLatin(temp);// todo: benski> changed back to local to keep old winamp tagged files working
id3v2.AddFrame(f, TRUE);
}
}
}
int ID3v2::SetString(const char *tag, const wchar_t *data)
{
if (!_stricmp(tag, "artist"))
add_set_id3v2_frame(ID3FID_LEADARTIST, data);
else if (!_stricmp(tag, "album"))
add_set_id3v2_frame(ID3FID_ALBUM, data);
else if (!_stricmp(tag, "albumartist"))
{
add_set_id3v2_frame(ID3FID_BAND, data);
if (!data || !*data) // if we're deleting the field
{
ID3_AddUserText(&id3v2, L"ALBUM ARTIST", data); // delete this alternate field also, or it's gonna look like it didn't "take" with a fb2k file
ID3_AddUserText(&id3v2, L"ALBUMARTIST", data); // delete this alternate field also, or it's gonna look like it didn't "take" with an mp3tag file
ID3_AddUserText(&id3v2, L"Band", data); // delete this alternate field also, or it's gonna look like it didn't "take" with an audacity file
}
}
else if (!_stricmp(tag, "comment"))
ID3_AddSetComment(&id3v2, data);
else if (!_stricmp(tag, "title"))
add_set_id3v2_frame(ID3FID_TITLE, data);
else if (!_stricmp(tag, "year"))
{
add_set_id3v2_frame(ID3FID_YEAR, data);
if (id3v2.version >= 4) // work around the fact that our id3 code doesn't handle versioning like this too well
add_set_id3v2_frame(ID3FID_RECORDINGTIME, data);
else
add_set_id3v2_frame(ID3FID_RECORDINGTIME, (wchar_t *)0);
}
else if (!_stricmp(tag, "genre"))
add_set_id3v2_frame(ID3FID_CONTENTTYPE, data);
else if (!_stricmp(tag, "track"))
add_set_id3v2_frame(ID3FID_TRACKNUM, data);
else if (!_stricmp(tag, "disc"))
add_set_id3v2_frame(ID3FID_PARTINSET, data);
else if (!_stricmp(tag, "bpm"))
add_set_id3v2_frame(ID3FID_BPM, data);
else if (!_stricmp(tag, "rating"))
ID3_AddSetRating(&id3v2, data);
else if (!_stricmp(tag, "tool"))
add_set_id3v2_frame(ID3FID_ENCODEDBY, data);
else if (!_stricmp(tag, "composer"))
add_set_id3v2_frame(ID3FID_COMPOSER, data);
else if (!_stricmp(tag, "replaygain_track_gain"))
ID3_AddUserText(&id3v2, L"replaygain_track_gain", data, ENCODING_FORCE_ASCII);
else if (!_stricmp(tag, "replaygain_track_peak"))
ID3_AddUserText(&id3v2, L"replaygain_track_peak", data, ENCODING_FORCE_ASCII);
else if (!_stricmp(tag, "replaygain_album_gain"))
ID3_AddUserText(&id3v2, L"replaygain_album_gain", data, ENCODING_FORCE_ASCII);
else if (!_stricmp(tag, "replaygain_album_peak"))
ID3_AddUserText(&id3v2, L"replaygain_album_peak", data, ENCODING_FORCE_ASCII);
else if (!_stricmp(tag, "originalartist"))
add_set_id3v2_frame(ID3FID_ORIGARTIST, data);
else if (!_stricmp(tag, "encoder"))
add_set_id3v2_frame(ID3FID_ENCODERSETTINGS, data);
else if (!_stricmp(tag, "publisher"))
add_set_id3v2_frame(ID3FID_PUBLISHER, data);
else if (!_stricmp(tag, "copyright"))
add_set_id3v2_frame(ID3FID_COPYRIGHT, data);
else if (!_stricmp(tag, "compilation"))
add_set_id3v2_frame(ID3FID_COMPILATION, data);
else if (!_stricmp(tag, "remixing"))
add_set_id3v2_frame(ID3FID_MIXARTIST, data);
else if (!_stricmp(tag, "ISRC"))
add_set_id3v2_frame(ID3FID_ISRC, data);
else if (!_stricmp(tag, "url"))
add_set_latin_id3v2_frame(ID3FID_WWWUSER, data); // TODO: we should %## escape invalid characters
//add_set_id3v2_frame(ID3FID_WWWUSER, data);
else if (!_stricmp(tag, "GracenoteFileID"))
ID3_AddSetGracenoteTagID(&id3v2, data);
else if (!_stricmp(tag, "GracenoteExtData"))
{
ID3_AddUserText(&id3v2, L"GN_ExtData", data, ENCODING_FORCE_ASCII);
ID3_AddUserText(&id3v2, L"GN_ExtData",0); // delete this alternate field also
}
else if (!_stricmp(tag, "category"))
add_set_id3v2_frame(ID3FID_CONTENTGROUP, data);
else
return 0;
hasData=true;
dirty=true;
return 1;
}
void ID3v2::add_set_id3v2_frame(ID3_FrameID id, const wchar_t *c)
{
ID3_Frame *f = id3v2.Find(id);
if (!c || !*c)
{
if (f)
id3v2.RemoveFrame(f);
}
else
{
if (f)
{
SetFrameEncoding(f);
f->Field(ID3FN_TEXT).SetUnicode(c);
}
else
{
f = new ID3_Frame(id);
SetFrameEncoding(f);
f->Field(ID3FN_TEXT).SetUnicode(c);
id3v2.AddFrame(f, TRUE);
}
}
}
uint32_t ID3v2::EncodeSize()
{
if (!hasData)
return 0; // simple :)
return (uint32_t)id3v2.Size();
}
int ID3v2::Encode(const void *data, size_t len)
{
id3v2.Render((uchar *)data);
return 0;
}
static bool NameToAPICType(const wchar_t *name, int &num)
{
if (!name || !*name) // default to cover
num=0x3;
else if (!_wcsicmp(name, L"fileicon")) // 32x32 pixels 'file icon' (PNG only)
num=0x1;
else if (!_wcsicmp(name, L"icon")) // Other file icon
num=0x2;
else if (!_wcsicmp(name, L"cover")) // Cover (front)
num=0x3;
else if (!_wcsicmp(name, L"back")) // Cover (back)
num=0x4;
else if (!_wcsicmp(name, L"leaflet")) // Leaflet page
num=0x5;
else if (!_wcsicmp(name, L"media")) // Media (e.g. lable side of CD)
num=0x6;
else if (!_wcsicmp(name, L"leadartist")) //Lead artist/lead performer/soloist
num=0x7;
else if (!_wcsicmp(name, L"artist")) // Artist/performer
num=0x8;
else if (!_wcsicmp(name, L"conductor")) // Conductor
num=0x9;
else if (!_wcsicmp(name, L"band")) // Band/Orchestra
num=0xA;
else if (!_wcsicmp(name, L"composer")) // Composer
num=0xB;
else if (!_wcsicmp(name, L"lyricist")) // Lyricist/text writer
num=0xC;
else if (!_wcsicmp(name, L"location")) // Recording Location
num=0xD;
else if (!_wcsicmp(name, L"recording")) // During recording
num=0xE;
else if (!_wcsicmp(name, L"performance")) // During performance
num=0xF;
else if (!_wcsicmp(name, L"preview")) // Movie/video screen capture
num=0x10;
else if (!_wcsicmp(name, L"fish")) // A bright coloured fish
num=0x11;
else if (!_wcsicmp(name, L"illustration")) // Illustration
num=0x12;
else if (!_wcsicmp(name, L"artistlogo")) // Band/artist logotype
num=0x13;
else if (!_wcsicmp(name, L"publisherlogo")) // Publisher/Studio logotype
num=0x14;
else
return false;
return true;
}
int ID3v2::GetAlbumArt(const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType)
{
int pictype = 0;
if (NameToAPICType(type, pictype))
{
// try to get our specific picture type
ID3_Frame *frame = id3v2.Find(ID3FID_PICTURE, ID3FN_PICTURETYPE, pictype);
if (!frame && pictype == 3) // if not, just try a generic one
{
frame = id3v2.Find(ID3FID_PICTURE);
/*benski> CUT!
if (frame)
{
ID3_Field &field = frame->Field(ID3FN_PICTURETYPE);
if (field.Get())
frame=0;
}*/
}
if (frame)
{
char *fulltype = ID3_GetString(frame, ID3FN_MIMETYPE);
char *type = 0;
if (fulltype && *fulltype)
{
type = strchr(fulltype, '/');
}
if (type && *type)
{
type++;
char *type2 = strchr(type, '/');
if (type2 && *type2) type2++;
else type2 = type;
int typelen = MultiByteToWideChar(CP_ACP, 0, type2, -1, 0, 0);
*mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(typelen * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, type2, -1, *mimeType, typelen);
free(fulltype);
}
else
{
// attempt to work out a mime type from known 'invalid' values
if (fulltype && *fulltype)
{
if (!strcmpi(fulltype, "png") || !strcmpi(fulltype, "bmp") ||
!strcmpi(fulltype, "jpg") || !strcmpi(fulltype, "jpeg") ||
!strcmpi(fulltype, "gif"))
{
int typelen = MultiByteToWideChar(CP_ACP, 0, fulltype, -1, 0, 0);// + 6;
*mimeType = (wchar_t*)WASABI_API_MEMMGR->sysMalloc(typelen * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, fulltype, -1, *mimeType, typelen);
CharLowerBuff(*mimeType, typelen);
free(fulltype);
fulltype = 0;
}
if (0 != fulltype)
{
free(fulltype);
fulltype = 0;
}
}
else
{
*mimeType = 0; // unknown!
}
}
ID3_Field &field = frame->Field(ID3FN_DATA);
*len = field.Size();
*bits = WASABI_API_MEMMGR->sysMalloc(*len);
field.Get((uchar *)*bits, *len);
return ALBUMARTPROVIDER_SUCCESS;
}
}
return ALBUMARTPROVIDER_FAILURE;
}
int ID3v2::SetAlbumArt(const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType)
{
int pictype;
if (NameToAPICType(type, pictype))
{
// try to get our specific picture type
ID3_Frame *frame = id3v2.Find(ID3FID_PICTURE, ID3FN_PICTURETYPE, pictype);
if (!frame && pictype == 3) // if not, just try a generic one
{
frame = id3v2.Find(ID3FID_PICTURE);
/* benski> cut
if (frame)
{
ID3_Field &field = frame->Field(ID3FN_PICTURETYPE);
if (field.Get())
frame=0;
}*/
}
bool newFrame=false;
if (!frame)
{
frame = new ID3_Frame(ID3FID_PICTURE);
newFrame = true;
}
if (frame)
{
wchar_t mt[32] = {L"image/jpeg"};
if (mimeType)
{
if (wcsstr(mimeType, L"/") != 0)
{
StringCchCopyW(mt, 32, mimeType);
}
else
{
StringCchPrintfW(mt, 32, L"image/%s", mimeType);
}
}
frame->Field(ID3FN_MIMETYPE).SetLatin(AutoChar(mt, 28591));
frame->Field(ID3FN_PICTURETYPE).Set(pictype);
frame->Field(ID3FN_DESCRIPTION).Clear();
frame->Field(ID3FN_DATA).Set((uchar *)bits, len);
if (newFrame)
id3v2.AddFrame(frame, TRUE);
dirty=1;
return ALBUMARTPROVIDER_SUCCESS;
}
}
return ALBUMARTPROVIDER_FAILURE;
}
int ID3v2::DeleteAlbumArt(const wchar_t *type)
{
int pictype;
if (NameToAPICType(type, pictype))
{
// try to get our specific picture type
ID3_Frame *frame = id3v2.Find(ID3FID_PICTURE, ID3FN_PICTURETYPE, pictype);
if (!frame && pictype == 3) // if not, just try a generic one
{
frame = id3v2.Find(ID3FID_PICTURE);
/* benski> cut
if (frame)
{
ID3_Field &field = frame->Field(ID3FN_PICTURETYPE);
if (field.Get())
frame=0;
}
*/
}
if (frame)
{
id3v2.RemoveFrame(frame);
dirty=1;
return ALBUMARTPROVIDER_SUCCESS;
}
}
return ALBUMARTPROVIDER_FAILURE;
}
void ID3v2::Clear()
{
dirty=1;
hasData=false;
id3v2.Clear();
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef NULLSOFT_IN_MP3_ID3v2_H
#define NULLSOFT_IN_MP3_ID3v2_H
#include "../id3v2/id3_tag.h"
class ID3v2
{
public:
ID3v2();
bool HasData() { return hasData; }
bool IsDirty() { return dirty; }
int Decode(const void *data, size_t len);
int Encode(const void *data, size_t len);
uint32_t EncodeSize();
// return -1 for empty, 1 for OK, 0 for "don't understand tag name"
int GetString(const char *tag, wchar_t *data, int dataLen);
int SetString(const char *tag, const wchar_t *data);
int GetAlbumArt(const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType);
int SetAlbumArt(const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType);
int DeleteAlbumArt(const wchar_t *type);
void Clear();
private:
void add_set_id3v2_frame(ID3_FrameID id, const wchar_t *c);
void add_set_latin_id3v2_frame(ID3_FrameID id, const wchar_t *c);
bool hasData;
bool dirty;
public:
ID3_Tag id3v2;
};
#endif
+4
View File
@@ -0,0 +1,4 @@
#ifndef UNICODE_INPUT_PLUGIN
#define UNICODE_INPUT_PLUGIN
#endif
#include "../Winamp/in2.h"
+398
View File
@@ -0,0 +1,398 @@
#include "LAMEinfo.h"
#include <windows.h>
#include <memory.h>
#include <math.h>
#include "api__in_mp3.h"
#include "resource.h"
#include "in2.h"
#pragma intrinsic(memcmp)
extern In_Module mod;
// Xing header -
// 4 Xing
// 4 flags
// 4 frames
// 4 bytes
// 100 toc
// 4 bytes VBR quality
// Lame tag
// 9 bytes - release name
// 11
// Lame extended info tag
// http://gabriel.mp3-tech.org/mp3infotag.html
/*-------------------------------------------------------------*/
static int32_t ExtractI4(unsigned char *buf)
{
int x;
// big endian extract
x = buf[0];
x <<= 8;
x |= buf[1];
x <<= 8;
x |= buf[2];
x <<= 8;
x |= buf[3];
return x;
}
static int16_t ExtractI2(unsigned char *buf)
{
int x;
// big endian extract
x = buf[0];
x <<= 8;
x |= buf[1];
return x;
}
const static int bitrateV1L3[] = { 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 0};
const static int bitrateV1L1[] = { 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000, 0};
const static int bitrateV1L2[] = { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 0};
const static int bitrateV2L1[] = { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000, 0};
const static int bitrateV2L2L3[] = { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 0};
const static int sampleRateV1[] = {44100, 48000, 32000, 0};
const static int sampleRateV2[] = {22050, 24000, 16000, 0};
const static int sampleRateV2_5[] = {11025, 12000, 8000, 0};
// [mpeg_version][layer]
static const int samples_per_frame[4][4] =
{
// Layer 3, Layer 2, Layer 1
{ 0, 576, 1152, 384}, // MPEG2.5
{ 0, },
{ 0, 576, 1152, 384}, // MPEG2
{ 0, 1152, 1152, 384}, // MPEG1
};
void MPEGFrame::ReadBuffer(const unsigned char *buffer)
{
sync = ((unsigned short)buffer[0] << 3) | (buffer[1] >> 5);
mpegVersion = (buffer[1] >> 3) & 3;
layer = (buffer[1] >> 1) & 3;
protection = (buffer[1]) & 1;
bitrateIndex = (buffer[2] >> 4) & 0xF;
sampleRateIndex = (buffer[2] >> 2) & 3;
paddingBit = (buffer[2] >> 1) & 1;
privateBit = buffer[2] & 1;
channelMode = (buffer[3] >> 6) & 3;
modeExtension = (buffer[3] >> 4) & 3;
copyright = (buffer[3] >> 3) & 1;
original = (buffer[3] >> 2) & 1;
emphasis = (buffer[3]) & 3;
}
bool MPEGFrame::IsSync()
{
return sync == 0x07FF
&& layer != LayerError
&& mpegVersion != MPEG_Error
&& bitrateIndex != 15
&& bitrateIndex != 0
&& sampleRateIndex != 3
&& !(mpegVersion == MPEG2 && layer != Layer3)
&& !(mpegVersion == MPEG2_5 && layer != Layer3);
}
int MPEGFrame::GetBitrate()
{
switch (mpegVersion)
{
case MPEG1:
switch (layer)
{
case Layer1:
return bitrateV1L1[bitrateIndex];
case Layer2:
return bitrateV1L2[bitrateIndex];
case Layer3:
return bitrateV1L3[bitrateIndex];
}
break;
case MPEG2:
case MPEG2_5:
switch (layer)
{
case Layer1:
return bitrateV2L1[bitrateIndex];
case Layer2:
case Layer3:
return bitrateV2L2L3[bitrateIndex];
}
break;
}
return 0; // shouldn't get here
}
int MPEGFrame::GetPadding()
{
if (paddingBit == NotPadded)
return 0;
if (layer == Layer1)
return 4;
else
return 1;
}
int MPEGFrame::HeaderSize()
{
if (protection == CRC)
return 4 + 2; // 32bits frame header, 16bits CRC
else
return 4; // 32bits frame ehader
}
int MPEGFrame::GetSampleRate() const
{
switch(mpegVersion)
{
case MPEG1: return sampleRateV1[sampleRateIndex];
case MPEG2:return sampleRateV2[sampleRateIndex];
case MPEG2_5:return sampleRateV2_5[sampleRateIndex];
default: return 99999999; // return something that will hopefully cause the framesize to be 0
}
}
int MPEGFrame::GetSamplesPerFrame() const
{
return samples_per_frame[mpegVersion][layer];
}
bool MPEGFrame::IsCopyright()
{
return copyright == 1;
}
bool MPEGFrame::IsCRC()
{
return protection == CRC;
}
bool MPEGFrame::IsOriginal()
{
return original == 1;
}
const char *MPEGFrame::GetEmphasisString()
{
static char tempGE[32];
switch (emphasis)
{
case Emphasis_None:
return WASABI_API_LNGSTRING_BUF(IDS_NONE,tempGE,32);
case Emphasis_50_15_ms:
return WASABI_API_LNGSTRING_BUF(IDS_50_15_MICROSEC,tempGE,32);
case Emphasis_reserved:
return WASABI_API_LNGSTRING_BUF(IDS_INVALID,tempGE,32);
case Emphasis_CCIT_J_17:
return "CITT j.17";
default:
return WASABI_API_LNGSTRING_BUF(IDS_ERROR,tempGE,32);
}
}
int MPEGFrame::FrameSize()
{
if (layer == Layer1)
{
return (int)floor((48.0f*(float)GetBitrate())/GetSampleRate()) + GetPadding();
}
else if (layer == Layer2 || layer == Layer3)
{
if (mpegVersion == MPEG1)
return (int)floor((144.0f*(float)GetBitrate())/GetSampleRate()) + GetPadding();
else
return (int)floor((72.0f*(float)GetBitrate())/GetSampleRate()) + GetPadding();
}
return 0;
}
const char *MPEGFrame::GetMPEGVersionString()
{
switch(mpegVersion)
{
case MPEG1:
return "MPEG-1";
case MPEG2:
return "MPEG-2";
case MPEG2_5:
return "MPEG-2.5";
default:
static char tempMF[16];
return WASABI_API_LNGSTRING_BUF(IDS_ERROR,tempMF,16);
}
}
const char *MPEGFrame::GetChannelModeString()
{
static char tempGC[32];
switch(channelMode)
{
case Stereo:
return WASABI_API_LNGSTRING_BUF(IDS_STEREO,tempGC,32);
case JointStereo:
return WASABI_API_LNGSTRING_BUF(IDS_JOINT_STEREO,tempGC,32);
case DualChannel:
return WASABI_API_LNGSTRING_BUF(IDS_2_CHANNEL,tempGC,32);
case Mono:
return WASABI_API_LNGSTRING_BUF(IDS_MONO,tempGC,32);
default:
return WASABI_API_LNGSTRING_BUF(IDS_ERROR,tempGC,32);
}
}
int MPEGFrame::GetLayer()
{
switch(layer)
{
case Layer1:
return 1;
case Layer2:
return 2;
case Layer3:
return 3;
default:
return 0;
}
}
int MPEGFrame::GetNumChannels()
{
switch(channelMode)
{
case Stereo:
return 2;
case JointStereo:
return 2;
case DualChannel:
return 2;
case Mono:
return 1;
default:
return 0;
}
}
int ReadLAMEinfo(unsigned char *buffer, LAMEinfo *lameInfo)
{
int flags;
MPEGFrame frame;
frame.ReadBuffer(buffer);
if (!frame.IsSync())
return 0;
lameInfo->h_id = frame.mpegVersion & 1;
lameInfo->samprate = frame.GetSampleRate();
// determine offset of header
if (frame.mpegVersion == MPEGFrame::MPEG1) // MPEG 1
{
if (frame.channelMode == MPEGFrame::Mono)
buffer += (17 + 4);//frame.HeaderSize());
else
buffer += (32 + 4);//frame.HeaderSize());
}
else if (frame.mpegVersion == MPEGFrame::MPEG2) // MPEG 2
{
if (frame.channelMode == MPEGFrame::Mono)
buffer += (9 + 4);//frame.HeaderSize());
else
buffer += (17 + 4);//frame.HeaderSize());
}
else if (frame.mpegVersion == MPEGFrame::MPEG2_5) // MPEG 2
{
if (frame.channelMode == MPEGFrame::Mono)
buffer += (9 + 4);//frame.HeaderSize());
else
buffer += (17 + 4);//frame.HeaderSize());
}
if (!memcmp(buffer, "Info", 4))
lameInfo->cbr=1;
else if (memcmp(buffer, "Xing", 4) && memcmp(buffer, "Lame", 4))
return 0;
buffer += 4; // skip Xing tag
flags = lameInfo->flags = ExtractI4(buffer);
buffer += 4; // skip flags
if (flags & FRAMES_FLAG)
{
lameInfo->frames = ExtractI4(buffer);
buffer += 4; // skip frames
}
if (flags & BYTES_FLAG)
{
lameInfo->bytes = ExtractI4(buffer);
buffer += 4;
}
if (flags & TOC_FLAG)
{
if (lameInfo->toc)
{
for (int i = 0;i < 100;i++)
lameInfo->toc[i] = buffer[i];
}
buffer += 100;
}
lameInfo->vbr_scale = -1;
if (flags & VBR_SCALE_FLAG)
{
lameInfo->vbr_scale = ExtractI4(buffer);
buffer += 4;
}
if (!memcmp(buffer, "LAME", 4))
{
for (int i=0;i<9;i++)
lameInfo->lameTag[i]=*buffer++;
lameInfo->lameTag[9]=0; // null terminate in case tag used all 20 characters
lameInfo->encodingMethod = (*buffer++)&0xF; // we'll grab the VBR method
lameInfo->lowpass = (*buffer++)*100; // lowpass value
lameInfo->peak=*((float *)buffer); // read peak value
buffer+=4; // skip peak value
// read track gain
int16_t gain_word = ExtractI2(buffer);
if ((gain_word & 0xFC00) == 0x2C00)
{
lameInfo->replaygain_track_gain = (float)(gain_word & 0x01FF);
lameInfo->replaygain_track_gain /= 10;
if (gain_word & 0x0200)
lameInfo->replaygain_track_gain = -lameInfo->replaygain_track_gain;
}
buffer+=2;
// read album gain
gain_word = ExtractI2(buffer);
if ((gain_word & 0xFC00) == 0x4C00)
{
lameInfo->replaygain_album_gain = (float)(gain_word & 0x01FF);
lameInfo->replaygain_album_gain /= 10;
if (gain_word & 0x0200)
lameInfo->replaygain_album_gain = -lameInfo->replaygain_album_gain;
}
buffer+=2;
buffer+=1; // skip encoding flags + ATH type
buffer+=1; // skip bitrate
// get the encoder delay and padding, annoyingly as 12 bit values packed into 3 bytes
lameInfo->encoderDelay = ((unsigned short)buffer[0] << 4) | (buffer[1] >> 4);
lameInfo->padding = ((unsigned short)(buffer[1]&0x0F) << 8) | (buffer[2]);
}
return frame.FrameSize();
}
+118
View File
@@ -0,0 +1,118 @@
#ifndef NULLSOFT_LAMEINFOH
#define NULLSOFT_LAMEINFOH
#define FRAMES_FLAG 0x0001
#define BYTES_FLAG 0x0002
#define TOC_FLAG 0x0004
#define VBR_SCALE_FLAG 0x0008
#define FRAMES_AND_BYTES (FRAMES_FLAG | BYTES_FLAG)
#include <memory.h>
#pragma intrinsic(memset)
struct LAMEinfo
{
LAMEinfo()
{
memset(this, 0, sizeof(LAMEinfo));
}
int cbr; // set to 1 if the file is actually just CBR
// Xing
int h_id;
int samprate; // determined from MPEG header
int flags; // from Xing header data
int frames; // total bit stream frames from Xing header data
int bytes; // total bit stream bytes from Xing header data
int vbr_scale; // encoded vbr scale from Xing header data
unsigned char *toc; // pointer to unsigned char toc_buffer[100]
// may be NULL if toc not desired
// LAME
char lameTag[10]; // 9 characters, but we'll add an extra NULL just in case
float peak;
float replaygain_album_gain;
float replaygain_track_gain;
unsigned short lowpass;
unsigned short encoderDelay;
unsigned short padding;
int encodingMethod;
};
enum
{
ENCODING_METHOD_LAME = 0,
ENCODING_METHOD_CBR = 1,
ENCODING_METHOD_ABR = 2,
ENCODING_METHOD_VBR1 = 3,
ENCODING_METHOD_VBR2 = 4,
ENCODING_METHOD_VBR3 = 5,
ENCODING_METHOD_VBR4 = 6,
ENCODING_METHOD_CBR_2PASS = 8,
ENCODING_METHOD_ABR_2PASS = 9,
};
int ReadLAMEinfo(unsigned char *buffer, LAMEinfo *lameInfo);
class MPEGFrame
{
public:
int GetNumChannels();
void ReadBuffer(const unsigned char *buffer);
bool IsSync();
int GetBitrate();
int GetPadding();
int HeaderSize();
int GetSampleRate() const;
int FrameSize();
const char *GetMPEGVersionString();
const char *GetChannelModeString();
const char *GetEmphasisString();
int GetLayer();
bool IsCRC();
bool IsCopyright();
bool IsOriginal();
int MPEGFrame::GetSamplesPerFrame() const;
enum
{
NotPadded=0,
Padded=1,
CRC = 0,
NoProtection = 1,
Stereo = 0,
JointStereo = 1,
DualChannel = 2,
Mono = 3,
MPEG1 = 3,
MPEG2 = 2,
MPEG_Error = 1,
MPEG2_5 = 0,
Layer1 = 3,
Layer2 = 2,
Layer3 = 1,
LayerError = 0,
Emphasis_None = 0,
Emphasis_50_15_ms = 1,
Emphasis_reserved = 2,
Emphasis_CCIT_J_17 = 3,
};
unsigned int sync:11,
mpegVersion:2,
layer:2,
protection:1,
bitrateIndex:4,
paddingBit:1,
privateBit:1,
channelMode:2,
modeExtension:2,
sampleRateIndex:2,
copyright:1,
original:1,
emphasis:2;
};
#endif
+193
View File
@@ -0,0 +1,193 @@
#include <windows.h>
#include "Lyrics3.h"
#include "config.h"
#include <strsafe.h>
// http://www.id3.org/Lyrics3v2
Lyrics3::Lyrics3()
{
artist=0;
title=0;
album=0;
hasData=false;
dirty=false;
}
Lyrics3::~Lyrics3()
{
free(artist);
free(title);
free(album);
}
static wchar_t *CopyField(const uint8_t *buffer, uint32_t size)
{
int converted = MultiByteToWideChar(28591, 0,(LPCSTR)buffer, size, 0, 0);
wchar_t *str = (wchar_t *)calloc((converted+1), sizeof(wchar_t));
if (str)
{
converted = MultiByteToWideChar(28591, 0, (LPCSTR)buffer, size, str, converted);
str[converted]=0;
}
return str;
}
int Lyrics3::Decode(const void *data, size_t datalen)
{
if (!config_parse_lyrics3)
return 1;
if (memcmp(data, "LYRICSBEGIN", 11) == 0)
{
hasData = true;
datalen-=11;
uint8_t *buffer = (uint8_t *)data+11;
while (datalen > 8)
{
uint8_t fid[4] = {0};
uint8_t sizeT[6] = {0};
uint32_t size;
fid[3] = 0;
sizeT[5] = 0;
memcpy(fid, buffer, 3);
buffer+=3; datalen-=3;
memcpy(sizeT, buffer, 5);
buffer+=5; datalen-=5;
size = strtoul((char *)sizeT, 0, 10);
if (datalen >= size)
{
/*if ( memcmp(fid, "IND", 3) == 0) // the IND field
{
if ( buff2[ posn + 8 + 1 ] == '1')
stampsUsed = true;
}
else */
if (memcmp(fid, "ETT", 3) == 0) // the TITLE field
{
title = CopyField(buffer, size);
}
else if (strcmp((char *) fid, "EAR") == 0) // the ARTIST field
{
artist = CopyField(buffer, size);
}
else if (strcmp((char *) fid, "EAL") == 0) // the ALBUM field
{
album = CopyField(buffer, size);
}
/*else if ( strcmp((char *) fid, "LYR") == 0) // the LYRICS field
{
char *text;
luint newSize;
newSize = ID3_CRLFtoLF((char *) & buff2[ posn + 8 ], size);
if ( stampsUsed)
newSize = ID3_StripTimeStamps((char *) & buff2[ posn + 8 ], newSize);
if ( text = (char*)malloc(newSize + 1))
{
text[ newSize ] = 0;
memcpy( text, &buff2[ posn + 8 ], newSize);
ID3_AddLyrics( this, text);
free(text);
}
else
ID3_THROW( ID3E_NoMemory);
}*/
datalen-=size;
buffer+=size;
}
else
break;
}
return 0;
}
return 1;
}
int Lyrics3::GetString(const char *tag, wchar_t *data, int dataLen)
{
if (!hasData)
return 0;
if (!_stricmp(tag, "title"))
{
if (title && *title)
{
StringCchCopyW(data, dataLen, title);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "artist"))
{
if (artist && *artist)
{
StringCchCopyW(data, dataLen, artist);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "album"))
{
if (album && *album)
{
StringCchCopyW(data, dataLen, album);
return 1;
}
return -1;
}
return 0;
}
int Lyrics3::SetString(const char *tag, const wchar_t *data)
{
int ret=0;
if (!_stricmp(tag, "title"))
{
if (title) free(title);
title = _wcsdup(data);
ret = 1;
}
else if (!_stricmp(tag, "artist"))
{
if ( artist ) free(artist);
artist = _wcsdup(data);
ret = 1;
}
else if (!_stricmp(tag, "album"))
{
if ( album ) free(album);
album = _wcsdup(data);
ret = 1;
}
if(ret)
{
hasData=true;
}
return ret;
}
void Lyrics3::Clear()
{
free(artist); artist=0;
free(album); album=0;
free(title); title=0;
dirty=true;
hasData=false;
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef NULLSOFT_IN_MP3_LYRICS3_H
#define NULLSOFT_IN_MP3_LYRICS3_H
#include <bfc/platform/types.h>
class Lyrics3
{
public:
Lyrics3();
~Lyrics3();
bool HasData() { return hasData; }
bool IsDirty() { return dirty; }
void Clear();
void ResetDirty() { dirty=0; };
int Decode(const void *data, size_t datalen);
// return -1 for empty, 1 for OK, 0 for "don't understand tag name"
int GetString(const char *tag, wchar_t *data, int dataLen);
int SetString(const char *tag, const wchar_t *data);
private:
bool hasData;
bool dirty;
wchar_t *title, *album, *artist;
};
#endif
+612
View File
@@ -0,0 +1,612 @@
#include "main.h"
#include "LAMEInfo.h"
#include "AACFrame.h"
#include "config.h"
#include "../winamp/wa_ipc.h"
#include <Richedit.h>
#include "api__in_mp3.h"
#include "FactoryHelper.h"
#include <shlwapi.h>
#include <strsafe.h>
#include <foundation/error.h>
int fixAACCBRbitrate(int br);
#if 0
/*
*/
/*
int MP3Info::remove_id3v1()
{
char temp[3] = {0, 0, 0};
DWORD x;
int err = 0;
HANDLE hFile = CreateFile(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return 0; //1;
}
SetFilePointer(hFile, -128, NULL, FILE_END);
ReadFile(hFile, temp, 3, &x, NULL);
if (!memcmp(temp, "TAG", 3))
{
SetFilePointer(hFile, -128, NULL, FILE_END);
if (!SetEndOfFile(hFile))
{
err = 1;
}
}
CloseHandle(hFile);
if (!err) fbuf[0] = 0;
return err;
return 0;
}
*/
/*
da_tag.SetUnsync(false);
da_tag.SetExtendedHeader(true);
da_tag.SetCompression(false);
da_tag.SetPadding(true);
*/
#endif
int FindAverageAACBitrate(unsigned __int8 *data, int sizeBytes)
{
AACFrame aacFrame;
aacFrame.ReadBuffer(data);
if (aacFrame.OK())
{
int aac_frame_length = aacFrame.frameLength;
int no_rawdb = aacFrame.numDataBlocks;
int fc_tot = aac_frame_length;
int fc_cnt = no_rawdb + 1;
unsigned char *aa = data + aac_frame_length;
int tt = sizeBytes - aac_frame_length;
while (tt >= 8)
{
AACFrame nextFrame;
nextFrame.ReadBuffer(aa);
if (!nextFrame.OK()) break; // error
int fcaac_frame_length = nextFrame.frameLength;
int fcno_rawdb = nextFrame.numDataBlocks;
fc_cnt += fcno_rawdb + 1;
fc_tot += fcaac_frame_length;
aa += fcaac_frame_length;
tt -= fcaac_frame_length;
}
int avg_framesize = fc_tot / (fc_cnt ? fc_cnt : 1);
return fixAACCBRbitrate(MulDiv(avg_framesize * 8, aacFrame.GetSampleRate(), 1024 * 1000));
}
return 0;
}
static bool ScanForFrame(CGioFile *file, int *bytesRead)
{
unsigned char buffer[512] = {0}; /* don't want to read too much, since most MP3's start at 0 */
int buflen = 0;
int checked=0;
if (file->Peek(buffer, sizeof(buffer), &buflen) != NErr_Success)
return false;
unsigned char *b = buffer;
while (buflen >= 4)
{
MPEGFrame frame1;
frame1.ReadBuffer(b);
if (frame1.IsSync())
{
if (checked)
file->Read(buffer, checked, &buflen);
*bytesRead=checked;
return true;
}
checked++;
buflen--;
b++;
}
if (checked)
file->Read(buffer, checked, &buflen);
*bytesRead=checked;
return false;
}
static bool mp3sync(CGioFile *file)
{
unsigned char buffer[1448 + 4] = {0}; /* large enough for one max-size frame and the header of the second */
int buflen = 0;
static const unsigned long gdwHeaderSyncMask = 0xfffe0c00L;
unsigned long ulHdr1=0;
unsigned long ulHdr2=0;
int bytesChecked=0;
while (bytesChecked<32768)
{
int bytesRead=0;
if (ScanForFrame(file, &bytesRead))
{
if (file->Peek(buffer, sizeof(buffer), &buflen) != NErr_Success)
return false;
if (buflen >= 4)
{
MPEGFrame frame1;
frame1.ReadBuffer(buffer);
if (frame1.IsSync())
{
ulHdr1 = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
int framelength= frame1.FrameSize();
if (buflen >= (framelength+4))
{
unsigned char *b = buffer + framelength;
buflen -= frame1.FrameSize();
MPEGFrame frame2;
frame2.ReadBuffer(b);
ulHdr2 = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
if (!((ulHdr1 ^ ulHdr2) & gdwHeaderSyncMask) && frame2.IsSync())
return true;
else
{
}
}
}
file->Read(buffer, 1, &buflen);
bytesChecked++;
}
}
else if (file->EndOf())
return 0;
bytesChecked+=bytesRead;
}
return false;
}
static const wchar_t *GetMPEGVersionString(int mpegVersion)
{
switch (mpegVersion)
{
case MPEGFrame::MPEG1:
return L"MPEG-1";
case MPEGFrame::MPEG2:
return L"MPEG-2";
case MPEGFrame::MPEG2_5:
return L"MPEG-2.5";
default:
static wchar_t temp[64];
return WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,temp,64);
}
}
static const wchar_t *GetEmphasisString(int emphasis)
{
static wchar_t tempE[32];
switch (emphasis)
{
case 0:
return WASABI_API_LNGSTRINGW_BUF(IDS_NONE,tempE,32);
case 1:
return WASABI_API_LNGSTRINGW_BUF(IDS_50_15_MICROSEC,tempE,32);
case 2:
return WASABI_API_LNGSTRINGW_BUF(IDS_INVALID,tempE,32);
case 3:
return L"CITT j.17";
default:
return WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,tempE,32);
}
}
static const wchar_t *GetChannelModeString(int channelMode)
{
static wchar_t tempM[32];
switch (channelMode)
{
case 0:
return WASABI_API_LNGSTRINGW_BUF(IDS_STEREO,tempM,32);
case 1:
return WASABI_API_LNGSTRINGW_BUF(IDS_JOINT_STEREO,tempM,32);
case 2:
return WASABI_API_LNGSTRINGW_BUF(IDS_2_CHANNEL,tempM,32);
case 3:
return WASABI_API_LNGSTRINGW_BUF(IDS_MONO,tempM,32);
default:
return WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,tempM,32);
}
}
#define INFO_READ_SIZE 32768
void GetFileDescription(const wchar_t *file, CGioFile &_file, wchar_t *data, size_t datalen)
{
int hdroffs = 0;
size_t size = datalen;
wchar_t *mt = data;
wchar_t *ext = PathFindExtension(file);
wchar_t langbuf[256] = {0};
int flen = _file.GetContentLength();
StringCchPrintfExW(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_PAYLOAD_SIZE, langbuf, 256), _file.GetContentLength());
if (!_wcsicmp(ext, L".aac") || !_wcsicmp(ext, L".vlb"))
{
#if 0 // TODO!
if (_wcsicmp(ext, L".vlb")) // aacplus can't do VLB
{
if (aacPlus)
{
aacPlus->EasyOpen(AACPLUSDEC_OUTPUTFORMAT_INT16_HOSTENDIAN, 6);
AACPLUSDEC_EXPERTSETTINGS *pConf = aacPlus->GetDecoderSettingsHandle();
pConf->bEnableOutputLimiter = 1;
pConf->bDoUpsampling = 1;
aacPlus->SetDecoderSettings();
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW_BUF(IDS_FORMAT_AAC, langbuf, 256), &mt, &size, 0);
char buffer[INFO_READ_SIZE] = {0};
int inputRead;
_file.Read(buffer, INFO_READ_SIZE, &inputRead);
AACPLUSDEC_BITSTREAMBUFFERINFO bitbufInfo = { inputRead, 0, 0};
aacPlus->StreamFeed((unsigned char *)buffer, &bitbufInfo);
unsigned char tempBuf[65536] = {0}; // grr, can't we find a better way to do this?
AACPLUSDEC_AUDIOBUFFERINFO audioBufInfo = {65536, 0, 0};
aacPlus->StreamDecode(tempBuf, &audioBufInfo, 0, 0);
audioBufInfo.nBytesBufferSizeIn -= audioBufInfo.nBytesWrittenOut;
aacPlus->StreamDecode(tempBuf + audioBufInfo.nBytesWrittenOut, &audioBufInfo, 0, 0);
AACPLUSDEC_STREAMPROPERTIES *streamProperties = aacPlus->GetStreamPropertiesHandle();
if (streamProperties->nDecodingState == AACPLUSDEC_DECODINGSTATE_STREAMVERIFIED)
{
AACPLUSDEC_PROGRAMPROPERTIES *currentProgram = &(streamProperties->programProperties[streamProperties->nCurrentProgram]);
switch (currentProgram->nStreamType)
{
case AACPLUSDEC_MPEG2_PROFILE_AACMAIN:
StringCchCatEx(mt, size, L"\r\nMPEG-2 AAC", &mt, &size, 0);
break;
case AACPLUSDEC_MPEG2_PROFILE_AACLC:
if (currentProgram->bProgramSbrEnabled)
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW_BUF(IDS_MPEG2_HE_AAC_IS, langbuf, 256), &mt, &size, 0);
else
StringCchCatEx(mt, size, L"\r\nMPEG-2 AAC LC", &mt, &size, 0);
break;
case AACPLUSDEC_MPEG4_AOT_AACMAIN:
StringCchCatEx(mt, size, L"\r\nMPEG-4 AAC", &mt, &size, 0);
break;
case AACPLUSDEC_MPEG4_AOT_AACLC:
if (currentProgram->bProgramSbrEnabled)
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW_BUF(IDS_MPEG4_HE_AAC_IS, langbuf, 256), &mt, &size, 0);
else
StringCchCatEx(mt, size, L"\r\nMPEG-4 AAC LC", &mt, &size, 0);
break;
case AACPLUSDEC_MPEG4_AOT_SBR:
StringCchCatEx(mt, size, L"\r\nMPEG-4 HE-AAC", &mt, &size, 0);
break;
}
if (currentProgram->nAacSamplingRate != currentProgram->nOutputSamplingRate)
StringCchPrintfEx(mt, size, &mt, &size, 0,
WASABI_API_LNGSTRINGW(IDS_SAMPLE_RATE_OUTPUT),
currentProgram->nAacSamplingRate, currentProgram->nOutputSamplingRate);
else
StringCchPrintfEx(mt, size, &mt, &size, 0,
WASABI_API_LNGSTRINGW(IDS_SAMPLE_RATE),
currentProgram->nAacSamplingRate);
int srate = currentProgram->nOutputSamplingRate;
if (currentProgram->bProgramSbrEnabled)
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_SBR_PRESENT), &mt, &size, 0);
else
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_SBR_NOT_PRESENT), &mt, &size, 0);
if (currentProgram->nAacChannels != currentProgram->nOutputChannels)
StringCchPrintfEx(mt, size, &mt, &size, 0,
WASABI_API_LNGSTRINGW(IDS_CHANNELS_OUTPUT),
currentProgram->nAacChannels, currentProgram->nOutputChannels);
else
StringCchPrintfEx(mt, size, &mt, &size, 0,
WASABI_API_LNGSTRINGW(IDS_CHANNELS),
currentProgram->nAacChannels);
switch (currentProgram->nChannelMode)
{
case AACPLUSDEC_CHANNELMODE_MONO:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_MONO), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_STEREO:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_STEREO), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_PARAMETRIC_STEREO:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_PARAMETRIC_STEREO), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_DUAL_CHANNEL:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_DUAL_CHANNEL), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_4_CHANNEL_2CPE:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_4_CHANNEL_2_CPE), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_4_CHANNEL_MPEG:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_4_CHANNEL_MPEG), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_5_CHANNEL:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_5_CHANNEL), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_5_1_CHANNEL:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_5_1), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_6_1_CHANNEL:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_6_1), &mt, &size, 0);
break;
case AACPLUSDEC_CHANNELMODE_7_1_CHANNEL:
StringCchCatEx(mt, size, WASABI_API_LNGSTRINGW(IDS_MODE_7_1), &mt, &size, 0);
break;
}
if (streamProperties->nBitrate)
{
StringCchPrintfEx(mt, size, &mt, &size, 0,
WASABI_API_LNGSTRINGW(IDS_BITRATE),
streamProperties->nBitrate);
}
else
{
int avg_bitrate = FindAverageAACBitrate((unsigned char *)buffer, inputRead);
StringCchPrintfEx(mt, size, &mt, &size, 0,
WASABI_API_LNGSTRINGW(IDS_AVERAGE_BITRATE),
avg_bitrate);
}
}
}
}
if (!aacPlus)
#endif
{
char buffer[INFO_READ_SIZE] = {0};
int inputRead = 0;
_file.Read(buffer, INFO_READ_SIZE, &inputRead);
StringCchCopyEx(mt, size, WASABI_API_LNGSTRINGW(IDS_FORMAT_AAC), &mt, &size, 0);
unsigned char *a = (unsigned char *)buffer;
while (inputRead-- >= 8)
{
AACFrame aacFrame;
aacFrame.ReadBuffer(a);
if (aacFrame.OK())
{
int aac_frame_length = aacFrame.frameLength;
int no_rawdb = aacFrame.numDataBlocks;
/*size_t size = 1024;
char *mt = mpeg_description;*/
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW(IDS_HEADER_FOUND_AT_X_BYTES), hdroffs);
StringCchPrintfEx(mt, size, &mt, &size, 0, L"\r\nMPEG-%d AAC", aacFrame.GetMPEGVersion());
int fc_tot = aac_frame_length;
int fc_cnt = no_rawdb + 1;
unsigned char *aa = a + aac_frame_length;
int tt = inputRead - aac_frame_length;
while (tt >= 8)
{
AACFrame nextFrame;
nextFrame.ReadBuffer(aa);
if (!nextFrame.OK()) break; // error
int fcaac_frame_length = nextFrame.frameLength;
int fcno_rawdb = nextFrame.numDataBlocks;
fc_cnt += fcno_rawdb + 1;
fc_tot += fcaac_frame_length;
aa += fcaac_frame_length;
tt -= fcaac_frame_length;
}
{
int avg_framesize = fc_tot / (fc_cnt ? fc_cnt : 1);
int srate = aacFrame.GetSampleRate();
int avg_bitrate = fixAACCBRbitrate(MulDiv(avg_framesize * 8, srate, 1024 * 1000));
int len_s = MulDiv(flen, 1024, avg_framesize * srate);
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW(IDS_LENGTH_X_SECONDS), len_s);
StringCchPrintfEx(mt, size, &mt, &size, 0, L"\r\nCBR %d kbps", avg_bitrate);
}
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW(IDS_PROFILE), aacFrame.GetProfileName());
StringCchPrintfEx(mt, size, &mt, &size, 0, L"\r\n%dHz %s", aacFrame.GetSampleRate(), aacFrame.GetChannelConfigurationName());
StringCchPrintfEx(mt, size, &mt, &size, 0, L"\r\nCRC: %s", WASABI_API_LNGSTRINGW((aacFrame.protection == 0 ? IDS_YES : IDS_NO)));
break;
}
a++;
hdroffs++;
}
}
}
else
{
unsigned char mp3syncbuf[INFO_READ_SIZE] = {0};
int inputRead = 0;
DWORD start = _file.GetCurrentPosition();
// find position of first sync
if (!mp3sync(&_file))
return;
int syncposition = _file.GetCurrentPosition()-start;
// advance to first sync
_file.Peek(mp3syncbuf, INFO_READ_SIZE, &inputRead);
unsigned int padding = 0;
unsigned int encoderDelay = 0;
MPEGFrame frame;
frame.ReadBuffer(mp3syncbuf);
int framelen = frame.FrameSize();
//const CMp3StreamInfo *info = decoder.GetStreamInfo();
//const CMpegHeader *header = decoder.m_Mbs.GetHdr();
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_HEADER_FOUND_AT_X_BYTES, langbuf, 256), _file.GetHeaderOffset() + syncposition);
if (!padding) padding = _file.postpad;
if (!encoderDelay) encoderDelay = _file.prepad;
if (padding || encoderDelay)
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ENC_DELAY_ZERO_PADDING, langbuf, 256), encoderDelay, padding);
int is_vbr_lens = _file.m_vbr_ms;
int iLen = (is_vbr_lens ? is_vbr_lens/1000 : ((flen * 8) / frame.GetBitrate()));
if(iLen > 0)
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_LENGTH_X_SECONDS, langbuf, 256), iLen);
else
{
float fLen = (is_vbr_lens ? is_vbr_lens/1000.0f : ((flen * 8.0f) / frame.GetBitrate()));
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_LENGTH_X_PART_SECONDS, langbuf, 256), fLen);
}
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_S_LAYER_X, langbuf, 256), GetMPEGVersionString(frame.mpegVersion), frame.GetLayer());
int frames = _file.m_vbr_frames;
int is_vbr = _file.m_vbr_flag || _file.m_vbr_hdr;
if (!is_vbr || _file.encodingMethod == ENCODING_METHOD_CBR)
{
if (frames)
{
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_X_KBIT, langbuf, 256), frame.GetBitrate() / 1000, frames);
}
else
{
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_X_KBIT_APPROX, langbuf, 256), frame.GetBitrate() / 1000, MulDiv(flen, 8, framelen));
}
}
else if (is_vbr && _file.encodingMethod == ENCODING_METHOD_ABR)
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_X_KBIT_ABR, langbuf, 256), _file.GetAvgVBRBitrate(), frames);
else
{
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_X_KBIT_VBR, langbuf, 256), _file.GetAvgVBRBitrate(), _file.m_vbr_hdr?L"I":L"", frames);
}
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_X_HZ_S, langbuf, 256), frame.GetSampleRate(), GetChannelModeString(frame.channelMode));
StringCchPrintfEx(mt, size, &mt, &size, 0, L"\r\nCRC: %s", WASABI_API_LNGSTRINGW_BUF((frame.CRC ? IDS_YES : IDS_NO), langbuf, 256));
wchar_t tmp[16] = {0};
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_COPYRIGHTED, langbuf, 256), WASABI_API_LNGSTRINGW_BUF((frame.copyright ? IDS_YES : IDS_NO),tmp,16));
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_ORIGINAL, langbuf, 256), WASABI_API_LNGSTRINGW_BUF((frame.original ? IDS_YES : IDS_NO),tmp,16));
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_EMPHASIS, langbuf, 256), GetEmphasisString(frame.emphasis));
if (_file.m_vbr_frame_len && !_file.lengthVerified)
StringCchPrintfEx(mt, size, &mt, &size, 0, WASABI_API_LNGSTRINGW_BUF(IDS_MP3_HAS_BEEN_MODIFIED_NOT_ALL_MAY_BE_CORRECT, langbuf, 256));
}
}
void GetAudioInfo(const wchar_t *filename, CGioFile *file, int *len, int *channels, int *bitrate, int *vbr, int *sr)
{
*bitrate=0;
*len=0;
*vbr=0;
*channels=0;
if (file)
{
wchar_t *ext = PathFindExtension(filename);
if (!_wcsicmp(ext, L".aac") || !_wcsicmp(ext, L".vlb"))
{
unsigned char t[INFO_READ_SIZE*2] = {0};
unsigned char *a = t;
int n = 0;
if (file->Read(t, sizeof(t), &n) != NErr_Success)
return;
while (n-- >= 8)
{
AACFrame aacFrame;
aacFrame.ReadBuffer(a);
if (aacFrame.OK())
{
int aac_frame_length = aacFrame.frameLength;
int fc_tot = aac_frame_length;
int fc_cnt = aacFrame.numDataBlocks + 1;
unsigned char *aa = a + aac_frame_length;
int tt = n - aac_frame_length;
while (tt >= 8 && aac_frame_length)
{
AACFrame nextFrame;
nextFrame.ReadBuffer(aa);
if (!nextFrame.OK()) break; // error
int fcaac_frame_length = nextFrame.frameLength;
int fcno_rawdb = nextFrame.numDataBlocks;
fc_cnt += fcno_rawdb + 1;
fc_tot += fcaac_frame_length;
aa += fcaac_frame_length;
tt -= fcaac_frame_length;
}
int avg_framesize = fc_tot / (fc_cnt ? fc_cnt : 1);
int br = MulDiv(avg_framesize * 8, aacFrame.GetSampleRate(), 1024);
*len = MulDiv(file->GetContentLength(), 1024*8, br);
*bitrate = fixAACCBRbitrate(br/1000)*1000;
*sr = aacFrame.GetSampleRate();
*channels = aacFrame.GetNumChannels();
break;
}
a++;
}
}
else
{
if (*bitrate = file->GetAvgVBRBitrate()*1000)
{
*len = file->m_vbr_ms;
*vbr = file->m_vbr_flag || file->m_vbr_hdr;
}
if (!mp3sync(file))
return;
unsigned char t[4] = {0};
int n = 0;
if (file->Peek(t, sizeof(t), &n) != NErr_Success)
return;
MPEGFrame frame;
frame.ReadBuffer(t);
if (frame.IsSync())
{
if (!*bitrate)
{
*bitrate = frame.GetBitrate();
*len = MulDiv(file->GetContentLength(), 1000*8, *bitrate);
}
*channels = frame.GetNumChannels();
*sr = frame.GetSampleRate();
}
}
}
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef NULLSOFT_IN_MP3_MP3_INFO_H
#define NULLSOFT_IN_MP3_MP3_INFO_H
#include "Metadata.h"
#include <windows.h>
class MP3Info
{
public:
MP3Info(const wchar_t *fn);
char mpeg_description[1024];
bool isOld();
void get_file_info();
int write_id3v1();
int remove_id3v1();
void display_id3v1(HWND hwndDlg);
void get_id3v1_values(HWND hwndDlg);
void display_id3v2(HWND hwndDlg);
void get_id3v2_values(HWND hwndDlg);
void write_id3v2(HWND hwndDlg);
void do_enable_id3v1(HWND hwndDlg, int en);
void do_enable_id3v2(HWND hwndDlg, int en);
BOOL CALLBACK id3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
int setExtendedFileInfoW(const char *data, wchar_t *val);
int writeExtendedFileInfo();
bool IsMe(const wchar_t *fn)
{
return !lstrcmpW(file, fn);
}
protected:
// Keep track of file timestamp for file system change notification handling
FILETIME last_write_time;
private:
void SetField(const wchar_t *value, wchar_t *&v2, char *v1, size_t v1size);
Metadata metadata;
wchar_t file[MAX_PATH];
};
#endif
+616
View File
@@ -0,0 +1,616 @@
#include "Metadata.h"
#include "main.h"
#include "api__in_mp3.h"
#include "LAMEInfo.h"
#include "AACFrame.h"
#include "config.h"
#include "LAMEInfo.h"
#include <shlwapi.h>
#include <assert.h>
#include <foundation/error.h>
#include <strsafe.h>
#define INFO_READ_SIZE 32768
Metadata::Metadata( CGioFile *_file, const wchar_t *_filename )
{
if ( !PathIsURL( _filename ) )
filename = _wcsdup( _filename );
ReadTags( _file );
if ( bitrate = _file->GetAvgVBRBitrate() * 1000 )
{
length_ms = _file->m_vbr_ms;
vbr = _file->m_vbr_flag || _file->m_vbr_hdr;
}
}
void GetFileDescription(const wchar_t *file, CGioFile &_file, wchar_t *data, size_t datalen);
void GetAudioInfo(const wchar_t *filename, CGioFile *file, int *len, int *channels, int *bitrate, int *vbr, int *sr);
int Metadata::Open(const wchar_t *_filename)
{
if ( filename && *filename )
free( filename );
filename = _wcsdup(_filename);
if (file.Open(filename, INFO_READ_SIZE/1024) != NErr_Success)
return 1;
GetAudioInfo(filename, &file, &length_ms, &channels, &bitrate, &vbr, &sampleRate);
ReadTags(&file);
file.Close();
return METADATA_SUCCESS;
}
Metadata::~Metadata()
{
if (filename)
{
free(filename);
filename=0;
}
}
void Metadata::ReadTags(CGioFile *_file)
{
// Process ID3v1
if (config_parse_id3v1)
{
void *id3v1_data = _file->GetID3v1();
if (id3v1_data)
id3v1.Decode(id3v1_data);
}
if (config_parse_id3v2)
{
uint32_t len = 0;
void *id3v2_data = _file->GetID3v2(&len);
if (id3v2_data)
id3v2.Decode(id3v2_data, len);
}
if (config_parse_lyrics3)
{
uint32_t len = 0;
void *lyrics3_data = _file->GetLyrics3(&len);
if (lyrics3_data)
lyrics3.Decode(lyrics3_data, len);
}
if (config_parse_apev2)
{
uint32_t len = 0;
void *apev2_data = _file->GetAPEv2(&len);
if (apev2_data)
apev2.Decode(apev2_data, len);
}
}
static int ID3Write(const wchar_t *filename, HANDLE infile, DWORD offset, void *data, DWORD len)
{
wchar_t tempFile[MAX_PATH] = {0};
StringCchCopyW(tempFile, MAX_PATH, filename);
PathRemoveExtension(tempFile);
StringCchCatW(tempFile, MAX_PATH, L".tmp");
// check to make sure the filename was actually different!
// benski> TODO: we should just try to mangle the filename more rather than totally bail out
if (!_wcsicmp(tempFile, filename))
return SAVE_ERROR_CANT_OPEN_TEMPFILE;
// TODO: overlapped I/O
HANDLE outfile = CreateFile(tempFile, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (outfile != INVALID_HANDLE_VALUE)
{
DWORD written=0;
if (data && len)
WriteFile(outfile, data, len, &written, NULL);
SetFilePointer(infile, offset, 0, FILE_BEGIN);
DWORD read=0;
do
{
char data[4096] = {0};
written = read = 0;
ReadFile(infile, data, 4096, &read, NULL);
if (read) WriteFile(outfile, data, read, &written, NULL);
}
while (read != 0);
CloseHandle(outfile);
CloseHandle(infile);
if (!MoveFile(tempFile, filename))
{
if (!CopyFile(tempFile, filename, FALSE))
{
DeleteFile(tempFile);
return SAVE_ERROR_ERROR_OVERWRITING;
}
DeleteFile(tempFile);
}
return SAVE_SUCCESS;
}
return SAVE_ERROR_CANT_OPEN_TEMPFILE;
}
bool Metadata::IsDirty()
{
return id3v1.IsDirty() || id3v2.IsDirty() || lyrics3.IsDirty() || apev2.IsDirty();
}
int Metadata::Save()
{
if (!IsDirty())
return SAVE_SUCCESS;
int err=SAVE_SUCCESS;
if (GetFileAttributes(filename)&FILE_ATTRIBUTE_READONLY)
return SAVE_ERROR_READONLY;
HANDLE metadataFile = CreateFile(filename, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (metadataFile == INVALID_HANDLE_VALUE)
return SAVE_ERROR_OPENING_FILE;
if (file.Open(filename, INFO_READ_SIZE/1024) != NErr_Success)
{
CloseHandle(metadataFile);
return SAVE_ERROR_OPENING_FILE;
}
bool strippedID3v1=false; // this flag will get set to true when we remove ID3v1 as a side effect of removing APEv2 or Lyrics3 (or ID3v2.4 end-tag if/when we implement)
bool strippedLyrics3=false;
/* Strip APEv2 */
if (config_parse_apev2 && config_write_apev2 && apev2.IsDirty())
{
uint32_t len = 0;
void *apev2_data = file.GetAPEv2(&len);
if (apev2_data)
{
uint32_t lyrics3_len = 0;
void *lyrics3_data = file.GetLyrics3(&lyrics3_len);
if (lyrics3_data)
SetFilePointer(metadataFile, -(LONG)(len + 15 + lyrics3_len + (file.GetID3v1()?128:0)), NULL, FILE_END);
else
SetFilePointer(metadataFile, -(LONG)(len + (file.GetID3v1()?128:0)), NULL, FILE_END);
SetEndOfFile(metadataFile);
strippedLyrics3=true;
strippedID3v1=true;
}
}
/* Strip Lyrics3 tag */
if (!strippedLyrics3 && config_parse_lyrics3 && lyrics3.IsDirty())
{
uint32_t len = 0;
void *lyrics3_data = file.GetLyrics3(&len);
if (lyrics3_data)
{
SetFilePointer(metadataFile, -(LONG)(len + 15 + (file.GetID3v1()?128:0)), NULL, FILE_END);
SetEndOfFile(metadataFile);
strippedID3v1=true;
}
}
/* Strip ID3v1(.1) tag */
if (!strippedID3v1 /* if we stripped lyrics3 tag, then we ended up stripping id3v1 also */
&& config_parse_id3v1 && config_write_id3v1 && id3v1.IsDirty())
{
if (file.GetID3v1()) // see if we have ID3v1
{
SetFilePointer(metadataFile, -128, NULL, FILE_END);
SetEndOfFile(metadataFile);
}
}
/* Write APEv2 */
if (config_parse_apev2 && config_write_apev2 && apev2.IsDirty() && apev2.HasData())
{
switch(config_apev2_header)
{
case ADD_HEADER:
apev2.SetFlags(APEv2::FLAG_HEADER_HAS_HEADER, APEv2::FLAG_HEADER_HAS_HEADER);
break;
case REMOVE_HEADER:
apev2.SetFlags(0, APEv2::FLAG_HEADER_HAS_HEADER);
break;
}
size_t apev2_len = apev2.EncodeSize();
void *apev2_data = malloc(apev2_len);
if (apev2_data && apev2.Encode(apev2_data, apev2_len) == APEv2::APEV2_SUCCESS)
{
SetFilePointer(metadataFile, 0, NULL, FILE_END);
DWORD bytesWritten=0;
WriteFile(metadataFile, apev2_data, (DWORD)apev2_len, &bytesWritten, 0);
free(apev2_data);
apev2_data = 0;
if (bytesWritten != apev2_len)
{
err=SAVE_APEV2_WRITE_ERROR;
goto fail;
}
}
else
{
free(apev2_data);
apev2_data = 0;
err=SAVE_APEV2_WRITE_ERROR;
goto fail;
}
}
/* Write Lyrics3 */
if (strippedLyrics3) /* if we need to rewrite it because we stripped it (e.g. removing an APEv2 tag)*/
{
/* since we don't modify lyrics3 (yet) we'll just rewrite the original binary data */
uint32_t len = 0;
void *lyrics3_data = file.GetLyrics3(&len);
if (lyrics3_data)
{
SetFilePointer(metadataFile, 0, NULL, FILE_END);
DWORD bytesWritten=0;
WriteFile(metadataFile, lyrics3_data, len, &bytesWritten, NULL);
if (bytesWritten != len)
{
err=SAVE_LYRICS3_WRITE_ERROR;
goto fail;
}
char temp[7] = {0};
StringCchPrintfA(temp, 7, "%06u", len);
bytesWritten = 0;
WriteFile(metadataFile, temp, 6, &bytesWritten, NULL);
if (bytesWritten != 6)
{
err=SAVE_LYRICS3_WRITE_ERROR;
goto fail;
}
bytesWritten = 0;
WriteFile(metadataFile, "LYRICS200", 9, &bytesWritten, NULL);
if (bytesWritten != 9)
{
err=SAVE_LYRICS3_WRITE_ERROR;
goto fail;
}
}
}
/* Write ID3v1 */
if (config_parse_id3v1 && config_write_id3v1 && id3v1.IsDirty())
{
uint8_t id3v1_data[128] = {0};
if (id3v1.Encode(id3v1_data) == METADATA_SUCCESS)
{
SetFilePointer(metadataFile, 0, NULL, FILE_END);
DWORD bytesWritten=0;
WriteFile(metadataFile, id3v1_data, 128, &bytesWritten, NULL);
if (bytesWritten != 128)
{
err=SAVE_ID3V1_WRITE_ERROR;
goto fail;
}
}
}
else if (strippedID3v1)
{
/** if we stripped lyrics3 or apev2 but didn't modify id3v1 (or are configured not to use it),
** we need to rewrite it back to the original data
**/
void *id3v1_data=file.GetID3v1();
if (id3v1_data)
{
SetFilePointer(metadataFile, 0, NULL, FILE_END);
DWORD bytesWritten=0;
WriteFile(metadataFile, id3v1_data, 128, &bytesWritten, NULL);
if (bytesWritten != 128)
{
err=SAVE_ID3V1_WRITE_ERROR;
goto fail;
}
}
}
/* Write ID3v2 */
if (config_parse_id3v2 && config_write_id3v2 && id3v2.IsDirty())
{
uint32_t oldlen=0;
void *old_id3v2_data = file.GetID3v2(&oldlen);
id3v2.id3v2.SetPadding(false); // turn off padding to see if we can get away with non re-writing the file
uint32_t newlen = id3v2.EncodeSize();
if (old_id3v2_data && !newlen) // there's an old tag, but no new tag
{
err = ID3Write(filename, metadataFile, oldlen, 0, 0);
if (err == SAVE_SUCCESS)
metadataFile = INVALID_HANDLE_VALUE; // ID3Write returns true if it closed the handle
else
goto fail;
}
else if (!old_id3v2_data && !newlen) // no old tag, no new tag.. easy :)
{
}
else
{
id3v2.id3v2.SetPadding(true);
if (newlen <= oldlen) // if we can fit in the old tag
{
if (oldlen != newlen)
id3v2.id3v2.ForcePading(oldlen-newlen); // pad out the rest of the tag
else
id3v2.id3v2.SetPadding(false);
assert(id3v2.EncodeSize() == oldlen);
newlen = oldlen;
uint8_t *new_id3v2_data = (uint8_t *)calloc(newlen, sizeof(uint8_t));
if (new_id3v2_data && id3v2.Encode(new_id3v2_data, newlen) == METADATA_SUCCESS)
{
// TODO: deal with files with multiple starting id3v2 tags
SetFilePointer(metadataFile, 0, NULL, FILE_BEGIN);
DWORD bytesWritten=0;
WriteFile(metadataFile, new_id3v2_data, newlen, &bytesWritten, NULL);
free(new_id3v2_data);
new_id3v2_data = 0;
if (bytesWritten != newlen)
{
err = SAVE_ID3V2_WRITE_ERROR;
goto fail;
}
}
else
{
free(new_id3v2_data);
new_id3v2_data = 0;
err = SAVE_ID3V2_WRITE_ERROR;
goto fail;
}
}
else // otherwise we have to pad out the start
{
newlen = id3v2.EncodeSize();
uint8_t *new_id3v2_data = (uint8_t *)calloc(newlen, sizeof(uint8_t));
if (new_id3v2_data && id3v2.Encode(new_id3v2_data, newlen) == METADATA_SUCCESS)
{
// TODO: deal with files with multiple starting id3v2 tags
SetFilePointer(metadataFile, 0, NULL, FILE_BEGIN);
DWORD bytesWritten=0;
err = ID3Write(filename, metadataFile, oldlen, new_id3v2_data, newlen);
free(new_id3v2_data);
new_id3v2_data = 0;
if (err == SAVE_SUCCESS)
metadataFile = INVALID_HANDLE_VALUE; // ID3Write returns true if it closed the handle
else
goto fail;
}
else
{
free(new_id3v2_data);
new_id3v2_data = 0;
err = SAVE_ID3V2_WRITE_ERROR;
goto fail;
}
}
}
}
fail:
file.Close();
if (metadataFile != INVALID_HANDLE_VALUE)
CloseHandle(metadataFile);
return err;
}
int Metadata::GetExtendedData(const char *tag, wchar_t *data, int dataLen)
{
int understood=0;
switch (id3v2.GetString(tag, data, dataLen))
{
case -1:
data[0]=0;
understood=1;
break;
case 1:
return 1;
}
switch (apev2.GetString(tag, data, dataLen))
{
case -1:
data[0]=0;
understood=1;
break;
case 1:
return 1;
}
switch (lyrics3.GetString(tag, data, dataLen))
{
case -1:
data[0]=0;
understood=1;
break;
case 1:
return 1;
}
switch (id3v1.GetString(tag, data, dataLen))
{
case -1:
data[0]=0;
understood=1;
break;
case 1:
return 1;
}
switch (GetString(tag, data, dataLen))
{
case -1:
data[0]=0;
understood=1;
break;
case 1:
return 1;
}
return understood;
}
int Metadata::SetExtendedData(const char *tag, const wchar_t *data)
{
int understood=0;
if (config_create_id3v2 || id3v2.HasData())
understood |= id3v2.SetString(tag, data);
if (config_create_apev2 || apev2.HasData())
understood |= apev2.SetString(tag, data);
if (config_create_id3v1 || id3v1.HasData())
understood |= id3v1.SetString(tag, data);
return understood;
}
int Metadata::GetString(const char *tag, wchar_t *data, int dataLen)
{
if (!_stricmp(tag, "formatinformation"))
{
data[0]=0;
if (filename)
{
if (file.Open(filename, INFO_READ_SIZE/1024) == NErr_Success)
GetFileDescription(filename, file, data, dataLen);
file.Close();
}
}
else if (!_stricmp(tag, "length"))
{
StringCchPrintfW(data, dataLen, L"%d", length_ms);
}
else if (!_stricmp(tag, "stereo"))
{
StringCchPrintfW(data, dataLen, L"%d", channels==2);
}
else if (!_stricmp(tag, "vbr"))
{
StringCchPrintfW(data, dataLen, L"%d", vbr);
}
else if (!_stricmp(tag, "bitrate"))
{
StringCchPrintfW(data, dataLen, L"%d", bitrate/1000);
}
else if (!_stricmp(tag, "gain"))
{
StringCchPrintfW(data, dataLen, L"%-+.2f dB", file.GetGain());
}
else if (!_stricmp(tag, "pregap"))
{
if (file.prepad)
{
StringCchPrintfW(data, dataLen, L"%u", file.prepad);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "postgap"))
{
if (file.prepad) // yes, we check for this because postpad could legitimately be 0
{
StringCchPrintfW(data, dataLen, L"%u", file.postpad);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "numsamples"))
{
if (file.m_vbr_samples)
{
StringCchPrintfW(data, dataLen, L"%I64u", file.m_vbr_samples);
return 1;
}
return -1;
}
else if (!_stricmp(tag, "endoffset"))
{
if (file.m_vbr_frames)
{
int totalFrames = file.m_vbr_frames;
if (totalFrames > 8)
{
int seekPoint = 0;
// we're using m_vbr_bytes here instead of file.ContentLength(), because we're already trusting the other LAME header info
#define MAX_SIZE_8_FRAMES (1448 * 8) // mp3 frames won't be ever be any bigger than this (320kbps 32000Hz + padding)
if (file.m_vbr_bytes > MAX_SIZE_8_FRAMES)
seekPoint = (int)(file.m_vbr_bytes - MAX_SIZE_8_FRAMES);
else
seekPoint = 0;
size_t offsets[8] = {0};
size_t offsetsRead = 0;
size_t offsetPosition = 0;
unsigned char header[6] = {0};
MPEGFrame frame;
if (file.Open(filename, INFO_READ_SIZE/1024) != NErr_Success)
return -1;
// first we need to sync
while (1)
{
file.SetCurrentPosition(seekPoint, CGioFile::GIO_FILE_BEGIN);
int read = 0;
file.Read(header, 6, &read);
if (read != 6)
break;
frame.ReadBuffer(header);
if (frame.IsSync() && frame.GetLayer() == 3)
{
// make sure this isn't false sync - see if we can get another sync...
int nextPoint = seekPoint + frame.FrameSize();
file.SetCurrentPosition(nextPoint, CGioFile::GIO_FILE_BEGIN);
file.Read(header, 6, &read);
if (read != 6) // must be EOF
break;
frame.ReadBuffer(header);
if (frame.IsSync() && frame.GetLayer() == 3)
break;
}
seekPoint++;
}
while (1)
{
file.SetCurrentPosition(seekPoint, CGioFile::GIO_FILE_BEGIN);
int read = 0;
file.Read(header, 6, &read);
if (read != 6)
break;
frame.ReadBuffer(header);
if (frame.IsSync() && frame.GetLayer() == 3)
{
offsets[offsetPosition] = seekPoint;
offsetPosition = (offsetPosition + 1) % 8;
offsetsRead++;
seekPoint += frame.FrameSize();
}
else
break;
}
if (offsetsRead >= 8)
{
StringCchPrintfW(data, dataLen, L"%I32d", offsets[offsetPosition] + file.m_vbr_frame_len);
file.Close();
return 1;
}
file.Close();
}
}
return -1;
}
else
return 0;
return 1;
}
int fixAACCBRbitrate(int br);
+64
View File
@@ -0,0 +1,64 @@
#ifndef NULLSOFT_IN_MP3_METADATA
#define NULLSOFT_IN_MP3_METADATA
#include "giofile.h"
#include "ID3v1.h"
#include "ID3v2.h"
#include "Lyrics3.h"
#include "apev2.h"
enum
{
METADATA_SUCCESS = 0,
SAVE_SUCCESS = 0,
SAVE_ERROR_OPENING_FILE = 1,
SAVE_ID3V1_WRITE_ERROR = 2,
SAVE_ID3V2_WRITE_ERROR = 3,
SAVE_ERROR_READONLY = 4,
SAVE_ERROR_CANT_OPEN_TEMPFILE = 5,
SAVE_ERROR_ERROR_OVERWRITING = 6,
SAVE_LYRICS3_WRITE_ERROR = 7,
SAVE_APEV2_WRITE_ERROR = 8,
};
class Metadata
{
public:
Metadata() {}
Metadata(CGioFile *_file, const wchar_t *_filename);
~Metadata();
int Open(const wchar_t *filename);
int GetExtendedData(const char *tag, wchar_t *data, int dataLen);
int SetExtendedData(const char *tag, const wchar_t *data);
int Save();
bool IsMe(const wchar_t *fn) { return filename && !_wcsicmp(filename, fn); }
void AddRef() { InterlockedIncrement(&refs); }
void Release() { if(!InterlockedDecrement(&refs)) delete this; }
private:
bool IsDirty();
void ReadTags(CGioFile *_file);
int GetString(const char *tag, wchar_t *data, int dataLen);
int sampleRate = 0;
int bitrate = 0;
int vbr = 0;
int channels = 0;
int length_ms = 0;
CGioFile file;
public:
ID3v1 id3v1;
ID3v2 id3v2;
Lyrics3 lyrics3;
APE apev2;
wchar_t *filename = 0;
protected:
volatile LONG refs = 1;
};
#endif
@@ -0,0 +1,62 @@
#include "MetadataFactory.h"
#include "api__in_mp3.h"
#include "WasabiMetadata.h"
static const char serviceName[] = "MP3 Stream Metadata Provider";
FOURCC MetadataFactory::GetServiceType()
{
return MP3StreamMetadata::getServiceType();
}
const char *MetadataFactory::GetServiceName()
{
return serviceName;
}
GUID MetadataFactory::GetGUID()
{
return MP3StreamMetadataGUID;
}
void *MetadataFactory::GetInterface(int global_lock)
{
return new MP3StreamMetadata;
}
int MetadataFactory::SupportNonLockingInterface()
{
return 1;
}
int MetadataFactory::ReleaseInterface(void *ifc)
{
//plugin.service->service_unlock(ifc);
svc_metaTag *metadata = static_cast<svc_metaTag *>(ifc);
MP3StreamMetadata *mp3metadata = static_cast<MP3StreamMetadata *>(metadata);
delete mp3metadata;
return 1;
}
const char *MetadataFactory::GetTestString()
{
return 0;
}
int MetadataFactory::ServiceNotify(int msg, int param1, int param2)
{
return 1;
}
#define CBCLASS MetadataFactory
START_DISPATCH;
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
CB(WASERVICEFACTORY_GETGUID, GetGUID)
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
END_DISPATCH;
#undef CBCLASS
@@ -0,0 +1,24 @@
#ifndef NULLSOFT_MP3_METADATAFACTORY_H
#define NULLSOFT_MP3_METADATAFACTORY_H
#include <api/service/waservicefactory.h>
#include <api/service/services.h>
class MetadataFactory : public waServiceFactory
{
public:
FOURCC GetServiceType();
const char *GetServiceName();
GUID GetGUID();
void *GetInterface(int global_lock);
int SupportNonLockingInterface();
int ReleaseInterface(void *ifc);
const char *GetTestString();
int ServiceNotify(int msg, int param1, int param2);
protected:
RECVS_DISPATCH;
};
#endif
+165
View File
@@ -0,0 +1,165 @@
#include "OFL.h"
#include "foundation/error.h"
static void crcofl(unsigned short crcPoly, unsigned short crcMask, unsigned long *crc, unsigned char byte)
{
int i;
for (i=0; i<8; i++)
{
unsigned short flag = (*crc) & crcMask ? 1:0;
flag ^= (byte & 0x80 ? 1 : 0);
(*crc)<<=1;
byte <<= 1;
if(flag)
(*crc) ^= crcPoly;
}
}
int OFL::GetGaps(size_t *pregap, size_t *postgap)
{
/* TODO: verify the postgap calculation */
if (codec_delay >= 529)
{
*pregap = codec_delay;
size_t endcut;
endcut = samples_per_frame - ((total_length + codec_delay) % samples_per_frame); // how many 0 samples had to be added?
*postgap = endcut;
return NErr_Success;
}
return NErr_Empty;
}
double OFL::GetLengthSeconds() const
{
return (double)GetSamples() / (double)sample_rate;
}
uint64_t OFL::GetSamples() const
{
return total_length;
}
uint32_t OFL::GetFrames() const
{
uint64_t real_samples = (total_length+codec_delay)*samples_per_frame;
return (uint32_t) (real_samples/samples_per_frame);
}
int OFL::Read(const MPEGFrame &header, const uint8_t *buffer, size_t buffer_len)
{
if (header.layer != MPEGFrame::Layer3)
return NErr_False;
sample_rate = header.GetSampleRate();
samples_per_frame = header.GetSamplesPerFrame();
if (header.channelMode == MPEGFrame::Mono)
{
if (header.mpegVersion == MPEGFrame::MPEG1)
{
// 0-9 : main_data_end
int16_t main_data_end = (buffer[0] << 1) | (buffer[1] >> 7);
// read the 2 part2_3_lengths out so we know how big the main data section is
uint16_t part2_3_length = ((buffer[2] & 0x3F) << 6) | (buffer[3]>>2); // bits 18-30
part2_3_length += ((buffer[9] & 0x7) << 9) | (buffer[10] << 1) | (buffer[11] >> 7) ; // bits 77-89
size_t offset = 17 + (part2_3_length+7)/8;
if (offset+9 < buffer_len && buffer[offset] == 0xb4)
{
unsigned long crc=255;
for (int i=0;i<9;i++)
crcofl(0x0045, 0x0080, &crc, buffer[offset+i]);
if ((crc & 0xFF) == buffer[offset+9])
{
total_length = (buffer[offset+3] << 24) | (buffer[offset+4] << 16) | (buffer[offset+5] << 8) | (buffer[offset+6]);
codec_delay = (buffer[offset+1] << 8) | (buffer[offset+2]);
additional_delay= (buffer[offset+7] << 8) | (buffer[offset+8]);
return NErr_Success;
}
}
}
else
{ // MPEG2 and 2.5
// 0-8 : main_data_end
uint16_t main_data_end = buffer[0];
// read the 2 part2_3_lengths out so we know how big the main data section is
uint16_t part2_3_length = ((buffer[1] & 0x7F) << 5) | (buffer[2]>>3); // bits 9-21
size_t offset = 9 + (part2_3_length+7)/8;
if (offset+9 < buffer_len && buffer[offset] == 0xb4)
{
unsigned long crc=255;
for (int i=0;i<9;i++)
crcofl(0x0045, 0x0080, &crc, buffer[offset+i]);
if ((crc & 0xFF) == buffer[offset+9])
{
total_length = (buffer[offset+3] << 24) | (buffer[offset+4] << 16) | (buffer[offset+5] << 8) | (buffer[offset+6]);
codec_delay = (buffer[offset+1] << 8) | (buffer[offset+2]);
additional_delay= (buffer[offset+7] << 8) | (buffer[offset+8]);
return NErr_Success;
}
}
}
}
else
{
if (header.mpegVersion == MPEGFrame::MPEG1)
{
// 0-9 : main_data_end
uint16_t main_data_end = (buffer[0] << 1) | (buffer[1] >> 7);
// read the 4 part2_3_lengths out so we know how big the main data section is
uint16_t part2_3_length = ((buffer[2] & 0xF) << 8) | buffer[3]; // bits 20-32
part2_3_length += ((buffer[9] & 0x1) << 11) | (buffer[10] << 3) | (buffer[11] >> 5) ; // bits 79-91
part2_3_length += ((buffer[17] & 0x3F) << 6) | (buffer[18] >> 2); // bits 138-150
part2_3_length += ((buffer[24] & 0x7) << 9) | (buffer[25] << 1) | (buffer[26] >> 7); // bits 197-209
size_t offset = 32 + (part2_3_length+7)/8;
if (offset+9 < buffer_len && buffer[offset] == 0xb4)
{
unsigned long crc=255;
for (int i=0;i<9;i++)
crcofl(0x0045, 0x0080, &crc, buffer[offset+i]);
if ((crc & 0xFF) == buffer[offset+9])
{
total_length = (buffer[offset+3] << 24) | (buffer[offset+4] << 16) | (buffer[offset+5] << 8) | (buffer[offset+6]);
codec_delay = (buffer[offset+1] << 8) | (buffer[offset+2]);
additional_delay= (buffer[offset+7] << 8) | (buffer[offset+8]);
return NErr_Success;
}
}
}
else
{ // MPEG2 and 2.5
// 0-8 : main_data_end
uint16_t main_data_end = buffer[0];
// read the 4 part2_3_lengths out so we know how big the main data section is
uint16_t part2_3_length = ((buffer[1] & 0x3F) << 6) | (buffer[2] >> 2); // bits 10-22
part2_3_length += ((buffer[8] & 0x7) << 9) | (buffer[9] << 1) | (buffer[10] >> 7) ; // bits 69-81
size_t offset = 17 + (part2_3_length+7)/8;
if (offset+9 < buffer_len && buffer[offset] == 0xb4)
{
unsigned long crc=255;
for (int i=0;i<9;i++)
crcofl(0x0045, 0x0080, &crc, buffer[offset+i]);
if ((crc & 0xFF) == buffer[offset+9])
{
total_length = (buffer[offset+3] << 24) | (buffer[offset+4] << 16) | (buffer[offset+5] << 8) | (buffer[offset+6]);
codec_delay = (buffer[offset+1] << 8) | (buffer[offset+2]);
additional_delay= (buffer[offset+7] << 8) | (buffer[offset+8]);
return NErr_Success;
}
}
}
}
return NErr_False;
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "LAMEInfo.h"
#include <bfc/platform/types.h>
class OFL
{
public:
int Read(const MPEGFrame &header, const uint8_t *buffer, size_t buffer_len);
double GetLengthSeconds() const;
uint64_t GetSamples() const;
uint32_t GetFrames() const;
int GetGaps(size_t *pregap, size_t *postgap);
private:
int samples_per_frame;
uint32_t total_length;
uint16_t codec_delay;
uint16_t additional_delay;
unsigned int sample_rate;
};
@@ -0,0 +1,84 @@
#include "RawMediaReader.h"
#include <limits.h>
bool IsMyExtension(const wchar_t *filename);
int RawMediaReaderService::CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **out_reader)
{
if (IsMyExtension(filename))
{
CGioFile *file = new CGioFile();
if (!file)
return NErr_OutOfMemory;
if (file->Open(filename, 0) != NErr_Success)
{
delete file;
return NErr_FileNotFound;
}
RawMediaReader *reader = new RawMediaReader(file);
if (!reader)
{
file->Close();
delete file;
return NErr_OutOfMemory;
}
*out_reader = reader;
return NErr_Success;
}
else
{
return NErr_False;
}
}
#define CBCLASS RawMediaReaderService
START_DISPATCH;
CB(CREATERAWMEDIAREADER, CreateRawMediaReader);
END_DISPATCH;
#undef CBCLASS
RawMediaReader::RawMediaReader(CGioFile *file) : file(file)
{}
int RawMediaReader::Read( void *buffer, size_t buffer_size, size_t *bytes_read )
{
if ( buffer_size > INT_MAX )
return NErr_BadParameter;
int file_bytes_read = 0;
int ret = file->Read( buffer, (int)buffer_size, &file_bytes_read );
if ( ret == NErr_Success )
{
*bytes_read = (size_t)file_bytes_read;
if ( !file_bytes_read && file->IsEof() )
return NErr_EndOfFile;
return NErr_Success;
}
else
return NErr_Error;
}
size_t RawMediaReader::Release()
{
file->Close();
delete file;
file = NULL;
delete this;
return 0;
}
#define CBCLASS RawMediaReader
START_DISPATCH;
CB( RELEASE, Release );
CB( RAW_READ, Read );
END_DISPATCH;
#undef CBCLASS
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "../Agave/DecodeFile/svc_raw_media_reader.h"
#include "../Agave/DecodeFile/ifc_raw_media_reader.h"
#include "giofile.h"
// {5EC19CF3-E1ED-4AA5-AFD3-8E93149692BD}
static const GUID mpeg_audio_raw_reader_guid =
{ 0x5ec19cf3, 0xe1ed, 0x4aa5, { 0xaf, 0xd3, 0x8e, 0x93, 0x14, 0x96, 0x92, 0xbd } };
class RawMediaReaderService : public svc_raw_media_reader
{
public:
static const char *getServiceName() { return "MPEG-1/2 Audio Raw Reader"; }
static GUID getServiceGuid() { return mpeg_audio_raw_reader_guid; }
int CreateRawMediaReader(const wchar_t *filename, ifc_raw_media_reader **reader);
protected:
RECVS_DISPATCH;
};
class RawMediaReader : public ifc_raw_media_reader
{
public:
RawMediaReader(CGioFile *file);
int Read(void *buffer, size_t buffer_size, size_t *bytes_read);
size_t Release();
protected:
RECVS_DISPATCH;
private:
CGioFile *file;
};
+44
View File
@@ -0,0 +1,44 @@
#include "Stopper.h"
#include "main.h"
#include "../Winamp/wa_ipc.h"
Stopper::Stopper() : isplaying(0), timems(0)
{
}
void Stopper::ChangeTracking(bool mode)
{
SendMessage(mod.hMainWindow, WM_USER, mode, IPC_ALLOW_PLAYTRACKING); // enable / disable stats updating
}
void Stopper::Stop()
{
isplaying = (int)SendMessage(mod.hMainWindow, WM_USER, 0, IPC_ISPLAYING);
if (isplaying)
{
ChangeTracking(0); // disable stats updating
timems = (int)SendMessage(mod.hMainWindow, WM_USER, 0, IPC_GETOUTPUTTIME);
SendMessage(mod.hMainWindow, WM_COMMAND, 40047, 0); // Stop
}
}
void Stopper::Play()
{
if (isplaying) // this works _most_ of the time, not sure why a small portion of the time it doesnt hrmph :/
// ideally we should replace it with a system that pauses the decode thread, closes its file,
// does the shit, and reopens and reseeks to the new offset. for gaplessness
{
if (timems)
{
m_force_seek = timems; // SendMessage(mod.hMainWindow,WM_USER,timems,106);
}
else m_force_seek = -1;
SendMessage(mod.hMainWindow, WM_COMMAND, 40045, 0); // Play
m_force_seek = -1;
if (isplaying & 2)
{
SendMessage(mod.hMainWindow, WM_COMMAND, 40046, 0); // Pause
}
ChangeTracking(1); // enable stats updating
}
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
class Stopper
{
public:
Stopper();
void ChangeTracking(bool);
void Stop();
void Play();
int isplaying, timems;
};
+9
View File
@@ -0,0 +1,9 @@
#include "main.h"
#include "MP3Info.h"
StreamInfo::StreamInfo(void *buffer) : ID3Info()
{
unsigned __int8 *header = (unsigned __int8 *)buffer;
da_tag.Parse(header, &header[ID3_TAGHEADERSIZE]);
GetID3V2Values();
}
@@ -0,0 +1,67 @@
#include "WasabiMetadata.h"
#include <shlwapi.h>
#include "../nu/AutoChar.h"
const wchar_t *MP3StreamMetadata::GetName()
{
return L"MP3 Stream Metadata";
}
GUID MP3StreamMetadata::getGUID()
{
return MP3StreamMetadataGUID;
}
int MP3StreamMetadata::getFlags()
{
return METATAG_FILE_INFO;
}
int MP3StreamMetadata::isOurFile(const wchar_t *filename)
{
if (PathIsURL(filename) && !_wcsicmp(PathFindExtension(filename), L".mp3"))
return 1;
else
return 0;
}
int MP3StreamMetadata::metaTag_open(const wchar_t *filename)
{
if (metadata.Open(filename) == METADATA_SUCCESS)
return METATAG_SUCCESS;
else
return METATAG_FAILED;
}
void MP3StreamMetadata::metaTag_close()
{
delete this;
}
int MP3StreamMetadata::getMetaData(const wchar_t *tag, __int8 *buf, int buflenBytes, int datatype)
{
if (datatype == METATYPE_STRING)
{
if (metadata.GetExtendedData(AutoChar(tag), (wchar_t *)buf, buflenBytes/sizeof(wchar_t)))
return METATAG_SUCCESS;
else
return METATAG_UNKNOWN_TAG;
}
else
return METATAG_FAILED;
}
#define CBCLASS MP3StreamMetadata
START_DISPATCH;
CB(SVC_METATAG_GETNAME,getName)
CB(SVC_METATAG_GETGUID,getGUID)
CB(SVC_METATAG_GETFLAGS,getFlags)
CB(SVC_METATAG_ISOURFILE,isOurFile)
CB(SVC_METATAG_OPEN,metaTag_open)
VCB(SVC_METATAG_CLOSE,metaTag_close)
//CB(SVC_METATAG_ENUMTAGS,enumSupportedTag)
//CB(SVC_METATAG_GETTAGSIZE,getTagSize)
CB(SVC_METATAG_GETMETADATA,getMetaData)
//CB(SVC_METATAG_SETMETADATA,setMetaData)
END_DISPATCH;
#undef CBCLASS
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "../Agave/Metadata/svc_metatag.h"
#include "Metadata.h"
// {9937E02D-205B-4964-86A9-F784D9C05F5D}
static const GUID MP3StreamMetadataGUID =
{ 0x9937e02d, 0x205b, 0x4964, { 0x86, 0xa9, 0xf7, 0x84, 0xd9, 0xc0, 0x5f, 0x5d } };
class MP3StreamMetadata : public svc_metaTag
{
private:
/* These methods are to be used by api_metadata */
const wchar_t *GetName();
GUID getGUID(); // this needs to be the same GUID that you use when registering your service factory
int getFlags(); // how this service gets its info
int isOurFile(const wchar_t *filename);
int metaTag_open(const wchar_t *filename);
void metaTag_close(); // self-destructs when this is called (you don't need to call serviceFactory->releaseInterface)
/* user API starts here */
const wchar_t *enumSupportedTag(int n, int *datatype = NULL); // returns a list of understood tags. might not be complete (see note [1])
int getTagSize(const wchar_t *tag, size_t *sizeBytes); // always gives you BYTES, not characters (be careful with your strings)
int getMetaData(const wchar_t *tag, __int8 *buf, int buflenBytes, int datatype = METATYPE_STRING); // buflen is BYTES, not characters (be careful with your strings)
int setMetaData(const wchar_t *tag, const __int8 *buf, int buflenBytes, int datatype = METATYPE_STRING);
private:
Metadata metadata;
RECVS_DISPATCH;
};
+576
View File
@@ -0,0 +1,576 @@
#include <windows.h>
#include "main.h"
#if 1
BOOL CALLBACK AboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
if (uMsg == WM_COMMAND && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) EndDialog(hwndDlg,0);
return 0;
}
#else
#include <commctrl.h>
#include ".\graphics\image.h"
#include ".\graphics\imagefilters.h"
#include <strsafe.h>
#define random( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))
HBITMAP LoadImageFromResource(INT_PTR handle);
#define LEGAL_COUNT 4
wchar_t *legal[] = {L"Copyright (C) 1998-2006 - Nullsoft, Inc.",
L"MPEG Layer-3 audio compression technology licensed by Fraunhofer IIS and THOMSON multimedia.",
L"VLB decoding copyright 1998-2002 by Dolby Laboratories, Inc. All rights reserved.",
L"AAC && aacPlus decoding copyright 1998-2006 by Coding Technologies, Inc. All rights reserved."};
HFONT fntPlugin, fntC, fntLegal;
HBRUSH brhDlgBG;
#define IMAGES_COUNT 6
#define IMAGES_INDEX_MY 0
#define IMAGES_INDEX_WA 1
#define IMAGES_INDEX_CT 2
#define IMAGES_INDEX_IIS 3
#define IMAGES_INDEX_ID3V2 4
#define IMAGES_INDEX_MP3S 5
RECT rectLogo[IMAGES_COUNT];
MLImage *imgLogo[IMAGES_COUNT] = {NULL, NULL, NULL, NULL, NULL, NULL};
MLImage *imgLlama = NULL, *imgLlamaOrig = NULL, *imgMy = NULL;
RECT rcLlama;
int idxSelected;
wchar_t *url[IMAGES_COUNT - 1] = { L"http://winamp.com/",
L"http://www.codingtechnologies.com/index.htm",
L"http://www.iis.fraunhofer.de/index.html",
L"http://www.id3.org/",
L"http://www.iis.fraunhofer.de/amm/download/mp3surround/index.html"};
HWND hwndTT;
wchar_t strTT[] = L"click here to visit this website";
#define TIMER_ID_WATERRENDER 1980
#define TIMER_ID_WATERPULSE 1978
#define TIMER_DELAY_WATERRENDER 48
#define TIMER_DELAY_WATERPULSE 12000
#define TIMER_ID_LLAMAFADE 1987
#define TIMER_DELAY_LLAMAFADE 200
#define TIMER_ID_LOADDATA 1959
#define TIMER_DELAY_LOADDATA 10
MLImage *tmpImage = NULL;
MLImageFilterWater *fltrWater = NULL;
HCURSOR curHand = NULL;
void about_OnInit(HWND hwndDlg);
void about_OnDestroy(HWND hwndDlg);
void about_OnMouseDown(HWND hwndDlg, int cx, int cy);
void about_OnMouseMove(HWND hwndDlg, int cx, int cy);
void about_OnDraw(HWND hwndDlg);
void timer_OnWaterPulse(HWND hwndDlg);
void timer_OnLlamaFade(HWND hwndDlg);
void timer_OnLoadData(HWND hwndDlg);
void SetRects(int cx, int cy)
{
int i, xl, yl;
i = IMAGES_INDEX_MY; xl = (cx - imgLogo[i]->GetWidth())/2; yl = 64;
if (imgLogo[i]) SetRect(&rectLogo[i], xl, yl, xl + imgLogo[i]->GetWidth(), yl + imgLogo[i]->GetHeight());
xl = 2; yl = 2; i = IMAGES_INDEX_WA;
if (imgLogo[i]) SetRect(&rectLogo[i], xl, yl, xl + imgLogo[i]->GetWidth(), yl + imgLogo[i]->GetHeight());
xl = 2; yl = cy - 88; i = IMAGES_INDEX_CT;
if (imgLogo[i]) SetRect(&rectLogo[i], xl, yl, xl + imgLogo[i]->GetWidth(), yl + imgLogo[i]->GetHeight());
xl = rectLogo[i].right; i = IMAGES_INDEX_IIS;
if (imgLogo[i]) SetRect(&rectLogo[i], xl, yl, xl + imgLogo[i]->GetWidth(), yl + imgLogo[i]->GetHeight());
xl = rectLogo[i].right; i = IMAGES_INDEX_ID3V2;
if (imgLogo[i]) SetRect(&rectLogo[i], xl, yl, xl + imgLogo[i]->GetWidth(), yl + imgLogo[i]->GetHeight());
xl = rectLogo[i].right; i = IMAGES_INDEX_MP3S;
if (imgLogo[i]) SetRect(&rectLogo[i], xl, yl, xl + imgLogo[i]->GetWidth(), yl + imgLogo[i]->GetHeight());
if(imgLlama) SetRect(&rcLlama, 2, 1, imgLlama->GetWidth() + 2, imgLlama->GetHeight() + 1);
}
void CreateToolTipWnd(HWND hwndDlg)
{
INITCOMMONCONTROLSEX iccex;
iccex.dwICC = ICC_WIN95_CLASSES;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCommonControlsEx(&iccex);
hwndTT = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL, mod.hDllInstance, NULL);
SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
void UpdateToolTips(HWND hwndDlg)
{
TOOLINFOW ti;
unsigned int uid = 0;
// delete tools
int ttCount = SendMessage(hwndTT, TTM_GETTOOLCOUNT, 0, 0);
for(int i = 0; i < ttCount; i++)
{
if (SendMessageW(hwndTT, TTM_ENUMTOOLSW, (WPARAM)i, (LPARAM)&ti)) SendMessageW(hwndTT, TTM_DELTOOLW, 0, (LPARAM)&ti);
}
/// add tools
for (int i = 1; i < IMAGES_COUNT -1; i++)
{
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = TTF_SUBCLASS;
ti.hwnd = hwndDlg;
ti.hinst = mod.hDllInstance;
ti.uId = uid;
ti.lpszText = strTT;
ti.rect = rectLogo[i];
SendMessageW(hwndTT, TTM_ADDTOOLW, 0, (LPARAM) (LPTOOLINFO) &ti);
}
}
BOOL CALLBACK AboutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
about_OnInit(hwndDlg);
break;
case WM_DESTROY:
about_OnDestroy(hwndDlg);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hwndDlg,0);
}
break;
case WM_SIZE:
if (wParam != SIZE_MINIMIZED)
{
SetRects(LOWORD(lParam), HIWORD(lParam));
UpdateToolTips(hwndDlg);
}
case WM_MOUSEMOVE:
about_OnMouseMove(hwndDlg, LOWORD(lParam), HIWORD(lParam));
break;
case WM_LBUTTONDOWN:
about_OnMouseDown(hwndDlg, LOWORD(lParam), HIWORD(lParam));
break;
case WM_PAINT:
about_OnDraw(hwndDlg);
break;
case WM_TIMER:
switch(wParam)
{
case TIMER_ID_WATERRENDER:
if (idxSelected != -1 && fltrWater)
{
fltrWater->Render(tmpImage, imgLogo[idxSelected]);
InvalidateRect(hwndDlg, &rectLogo[idxSelected], FALSE);
}
break;
case TIMER_ID_WATERPULSE:
timer_OnWaterPulse(hwndDlg);
break;
case TIMER_ID_LLAMAFADE:
timer_OnLlamaFade(hwndDlg);
break;
case TIMER_ID_LOADDATA:
timer_OnLoadData(hwndDlg);
break;
}
break;
case WM_CTLCOLORDLG:
return (BOOL)brhDlgBG;
break;
}
return 0;
}
void about_OnInit(HWND hwndDlg)
{
HDC hdc = GetDC(hwndDlg);
fntPlugin = CreateFontW(-MulDiv(20, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Microsoft Sans Serif");
fntC = CreateFontW(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, 0, L"Arial");
fntLegal = CreateFontW(-MulDiv(6, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, 0, L"Microsoft Sans Serif");
ReleaseDC(hwndDlg, hdc);
brhDlgBG = CreateSolidBrush(RGB(255,255,255));
SetTimer(hwndDlg, TIMER_ID_LOADDATA, TIMER_DELAY_LOADDATA, NULL);
}
void about_OnDestroy(HWND hwndDlg)
{
for (int i = 0; i < IMAGES_COUNT; i++)
{
if (imgLogo[i]) delete(imgLogo[i]);
imgLogo[i] = NULL;
}
if (imgLlama) delete(imgLlama);
imgLlama = NULL;
if (imgLlamaOrig) delete(imgLlamaOrig);
imgLlamaOrig = NULL;
if (imgMy) delete(imgMy);
imgMy = NULL;
if (fntPlugin) DeleteObject(fntPlugin);
if (fntC) DeleteObject(fntC);
if (fntLegal) DeleteObject(fntLegal);
fntPlugin = NULL;
fntC = NULL;
fntLegal = NULL;
if (brhDlgBG) DeleteObject(brhDlgBG);
brhDlgBG = NULL;
if (fltrWater) delete (fltrWater);
fltrWater = NULL;
if (tmpImage) delete(tmpImage);
tmpImage = NULL;
if (curHand) DestroyCursor(curHand);
curHand = NULL;
}
void about_OnMouseDown(HWND hwndDlg, int cx, int cy)
{
if (idxSelected == -1) return;
HCURSOR curWait = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32514/*OCR_WAIT*/), IMAGE_CURSOR, 0, 0, LR_DEFAULTCOLOR);
SetCursor(curWait);
ShellExecuteW(hwndDlg, L"open", url[idxSelected -1], NULL, L"c:\\", SW_SHOW);
SetCursor(curHand);
DestroyCursor(curWait);
}
void about_OnMouseMove(HWND hwndDlg, int cx, int cy)
{
POINT pt = {cx, cy};
int idxNew = -1;
for (int i = 1; i < IMAGES_COUNT - 1; i ++)
{
if (PtInRect(&rectLogo[i], pt))
{
if (!curHand)
{
curHand = (HCURSOR)LoadImage(mod.hDllInstance, MAKEINTRESOURCE(IDC_CUR_HAND), IMAGE_CURSOR, 0, 0, LR_DEFAULTCOLOR);
}
SetCursor(curHand);
idxNew = i;
}
}
if (idxNew != idxSelected)
{
// stop animation
KillTimer(hwndDlg, TIMER_ID_WATERPULSE);
KillTimer(hwndDlg, TIMER_ID_WATERRENDER);
if (idxSelected != -1) // redraw previously animated
{
InvalidateRect(hwndDlg, &rectLogo[idxSelected], FALSE);
}
// set new one
idxSelected = idxNew;
if (fltrWater) delete(fltrWater);
fltrWater = NULL;
if (tmpImage) delete(tmpImage);
tmpImage = NULL;
if (idxSelected != -1 && idxSelected != IMAGES_INDEX_WA) SetTimer(hwndDlg, TIMER_ID_WATERPULSE, 30, NULL); // start delay
}
}
void about_OnDraw(HWND hwndDlg)
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hwndDlg, &ps);
RECT rc, ri;
GetClientRect(hwndDlg, &rc);
// Draw Llama
RECT rl;
SetRect(&rl, rcLlama.left, rcLlama.top, rcLlama.right, rcLlama.bottom);
if (imgLlama && IntersectRect(&ri, &rl, &ps.rcPaint))
{
HRGN hrgn = CreateRectRgn(rcLlama.left, rcLlama.top, rcLlama.right, rcLlama.bottom);
HRGN hrgn1 = CreateRectRgn(rectLogo[IMAGES_INDEX_MY].left,
rectLogo[IMAGES_INDEX_MY].top,
rectLogo[IMAGES_INDEX_MY].right,
rectLogo[IMAGES_INDEX_MY].bottom);
CombineRgn(hrgn, hrgn, hrgn1, RGN_DIFF);
DeleteObject(hrgn1);
hrgn1 = CreateRectRgn(rectLogo[IMAGES_INDEX_WA].left,
rectLogo[IMAGES_INDEX_WA].top,
rectLogo[IMAGES_INDEX_WA].right,
rectLogo[IMAGES_INDEX_WA].bottom);
CombineRgn(hrgn, hrgn, hrgn1, RGN_DIFF);
SelectClipRgn(hdc, hrgn);
DeleteObject(hrgn);
DeleteObject(hrgn1);
imgLlama->Draw(hdc, rl.left, rl.top);
SelectClipRgn(hdc, NULL);
}
MLImage *img;
for (int i = 0; i < IMAGES_COUNT -1; i++)
{
if (IntersectRect(&ri, &rectLogo[i], &ps.rcPaint))
{
if (idxSelected == i && tmpImage)
{
img = tmpImage;
HRGN hrgn = CreateRectRgn(rectLogo[i].left + 3, rectLogo[i].top + 3 , rectLogo[i].right - 3, rectLogo[i].bottom - 3);
SelectClipRgn(hdc, hrgn);
DeleteObject(hrgn);
}
else img = imgLogo[i];
if (img == NULL || imgLlama == NULL) continue;
if (i == IMAGES_INDEX_MY)
{ // blend Llama First
MLImageFilter_Blend1(imgMy, img, 0, 0,
imgLlama->GetWidth() - (rectLogo[i].left - rcLlama.left), img->GetHeight(), imgLlama,
rectLogo[i].left - rcLlama.left, rectLogo[i].top - rcLlama.top, RGB(255,255,255));
img = imgMy;
}
img->Draw(hdc, rectLogo[i].left, rectLogo[i].top);
SelectClipRgn(hdc, NULL);
}
}
RECT rt;
SetBkMode(hdc, TRANSPARENT);
rc.left += 6;
rc.bottom -= 2;
rc.right -= 4;
HFONT oldF = NULL;
SetRect(&rt, rc.right - 192, rc.top, rc.right, rc.top + 16);
if (IntersectRect(&ri, &rt, &ps.rcPaint))
{
/// Nullsoft (c)
HFONT oldF = (HFONT)SelectObject(hdc, fntC);
SetTextColor(hdc, RGB(100,100,200));
DrawTextW(hdc, legal[0], -1, &rt, DT_LEFT | DT_SINGLELINE);
}
SetRect(&rt, rc.left - 2, rc.bottom - 33, rc.right, rc.bottom);
if (IntersectRect(&ri, &rt, &ps.rcPaint))
{
/// Separator
MoveToEx(hdc, rt.left, rt.top, NULL);
HPEN lp = CreatePen(PS_SOLID,1, RGB(190, 190, 190));
HPEN op = (HPEN)SelectObject(hdc, lp);
LineTo(hdc, rt.right, rt.top);
SelectObject(hdc, lp);
DeleteObject(lp);
/// Legal...
oldF = (oldF != NULL) ? oldF : (HFONT)SelectObject(hdc, fntLegal);
SetTextColor(hdc, RGB(0,0,0));
for(int i = 1; i < LEGAL_COUNT; i++)
{
int y = rc.bottom - (LEGAL_COUNT - i)*10;
SetRect(&rt, rc.left, y, rc.right, y +10);
if (IntersectRect(&ri, &rt, &ps.rcPaint))
DrawTextW(hdc, legal[i], -1, &rt, DT_LEFT | DT_SINGLELINE);
}
}
if (oldF != NULL) SelectObject(hdc, oldF);
EndPaint(hwndDlg, &ps);
}
void timer_OnLoadData(HWND hwndDlg)
{
static step = 0;
KillTimer(hwndDlg, TIMER_ID_LOADDATA);
RECT rc;
GetClientRect(hwndDlg, &rc);
for (int i = 0; i < IMAGES_COUNT; i++)
{
imgLogo[i] = new MLImage(LoadImageFromResource, TRUE);
imgLogo[i]->Load();
}
imgMy = new MLImage();
MLImage::Copy(imgMy, imgLogo[IMAGES_INDEX_MY]);
imgLlamaOrig = new MLImage(LoadImageFromResource, TRUE);
imgLlamaOrig->Load();
imgLlama = new MLImage();
MLImage::Copy(imgLlama, imgLlamaOrig);
CreateToolTipWnd(hwndDlg);
UpdateToolTips(hwndDlg);
idxSelected = -1;
SetRects(rc.right - rc.left, rc.bottom - rc.top);
InvalidateRect(hwndDlg, &rc, FALSE);
// SetTimer(hwndDlg, TIMER_ID_LLAMAFADE, TIMER_DELAY_LLAMAFADE, NULL);
}
void timer_OnWaterPulse(HWND hwndDlg)
{
if (idxSelected == -1) return;
BOOL startRender = (!fltrWater);
if(!fltrWater)
{
KillTimer(hwndDlg, TIMER_ID_WATERPULSE); // stop timer - will change to slower interval
fltrWater = new MLImageFilterWater();
fltrWater->CreateFor(imgLogo[idxSelected]);
tmpImage = new MLImage(imgLogo[idxSelected]->GetWidth(), imgLogo[idxSelected]->GetHeight());
}
int ow = imgLogo[idxSelected]->GetWidth();
int oh = imgLogo[idxSelected]->GetHeight();
for (int i = 0; i < oh*ow/1024; i++)
{
fltrWater->SineBlob(-1, -1, random(4,min(oh,ow)), 600, 0);
}
if (startRender)
{
SetTimer(hwndDlg, TIMER_ID_WATERRENDER, TIMER_DELAY_WATERRENDER, NULL);
SetTimer(hwndDlg, TIMER_ID_WATERPULSE, TIMER_DELAY_WATERPULSE, NULL);
}
}
void timer_OnLlamaFade(HWND hwndDlg)
{
static int c = -2;
static int step = 2;
c = c + step;
if (c > 30 && step > 0) {step = 0 - step; c = 30;}
else if (c < 0 && step < 0) { step = 0 - step; c = 0; }
MLImageFilter_Fader3(imgLlama, imgLlamaOrig, c);
InvalidateRect(hwndDlg, &rcLlama, FALSE);
}
HBITMAP LoadImageFromResource(INT_PTR handle)
{
int id = 0;
BOOL incSize;
MLImage *img = (MLImage*)handle;
if (img == imgLogo[IMAGES_INDEX_WA]) {id = IDB_LOGO_WAPLUGINS; incSize = FALSE;}
else if (img == imgLogo[IMAGES_INDEX_IIS]) {id = IDB_LOGO_IIS; incSize = TRUE;}
else if (img == imgLogo[IMAGES_INDEX_CT]) {id = IDB_LOGO_CODETECH; incSize = TRUE;}
else if (img == imgLogo[IMAGES_INDEX_ID3V2]) {id = IDB_LOGO_ID3V2; incSize = TRUE;}
else if (img == imgLogo[IMAGES_INDEX_MP3S]) {id = IDB_LOGO_MP3SURROUND; incSize = FALSE;} // because we don't use it for now
else if (img == imgLogo[IMAGES_INDEX_MY]) {id = IDB_LOGO_MY; incSize = FALSE;}
else if (img == imgLlamaOrig) {id = IDB_LLAMA; incSize = FALSE;}
if (id == 0) return NULL;
HBITMAP hbmp = LoadBitmap(mod.hDllInstance, MAKEINTRESOURCE(id));
if (hbmp == NULL) return hbmp;
if (incSize)
{// we want to add additional white border
HDC hdcWnd = GetWindowDC(NULL);
HDC hdcSrc = CreateCompatibleDC(hdcWnd);
HDC hdcDest = CreateCompatibleDC(hdcWnd);
BITMAP bmp;
GetObject(hbmp, sizeof(BITMAP), &bmp);
int extraW = 40;
int extraH = 16;
HBITMAP hbmpNew = CreateBitmap(bmp.bmWidth + extraW, bmp.bmHeight + extraH, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
SelectObject(hdcSrc, hbmp);
SelectObject(hdcDest, hbmpNew);
// fill borders
HBRUSH br = CreateSolidBrush(RGB(255,255,255));
RECT rc;
SetRect(&rc, 0,0, bmp.bmWidth + extraW, extraH/2);
FillRect(hdcDest, &rc, br);
SetRect(&rc, 0, bmp.bmHeight + extraH/2, bmp.bmWidth + extraW, bmp.bmHeight + extraH);
FillRect(hdcDest, &rc, br);
SetRect(&rc, 0, extraH/2, extraW/2, bmp.bmHeight + extraH/2);
FillRect(hdcDest, &rc, br);
SetRect(&rc, bmp.bmWidth + extraW/2, extraH/2, bmp.bmWidth + extraW, bmp.bmHeight + extraH/2);
FillRect(hdcDest, &rc, br);
// copy original
BitBlt(hdcDest, extraW/2, extraH/2, bmp.bmWidth, bmp.bmHeight, hdcSrc, 0,0, SRCCOPY);
DeleteObject(br);
DeleteObject(hbmp);
DeleteDC(hdcSrc);
DeleteDC(hdcDest);
ReleaseDC(NULL, hdcWnd);
hbmp = hbmpNew;
}
if (img == imgLogo[IMAGES_INDEX_MY])
{ // need to add vesion number
HDC hdcWnd = GetWindowDC(NULL);
HDC hdcSrc = CreateCompatibleDC(hdcWnd);
HDC hdcDest = CreateCompatibleDC(hdcWnd);
HFONT fnt = CreateFontW(-MulDiv(90, GetDeviceCaps(hdcDest, LOGPIXELSY), 72), 22, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, 0, L"Agency FB");
SelectObject(hdcDest, fnt);
char *ver = mod.description + lstrlen(mod.description);
while(ver != mod.description && *ver != ' ')
{
ver = CharPrevA(mod.description, ver);
}
if (*ver == ' ') ver++;
RECT rc;
SetRect(&rc, 0, 0, 0, 0);
DrawText(hdcDest, ver, -1, &rc, DT_CALCRECT | DT_RIGHT |DT_SINGLELINE);
int extraW = rc.right + 6;
int extraH = 16;
BITMAP bmp;
GetObject(hbmp, sizeof(BITMAP), &bmp);
HBITMAP hbmpNew = CreateBitmap(bmp.bmWidth + extraW, bmp.bmHeight + extraH, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
SelectObject(hdcSrc, hbmp);
SelectObject(hdcDest, hbmpNew);
// fill new area
HBRUSH br = CreateSolidBrush(RGB(255,255,255));
SetRect(&rc, bmp.bmWidth,0, bmp.bmWidth + extraW, bmp.bmHeight + extraH);
FillRect(hdcDest, &rc, br);
SetRect(&rc, 0,0, bmp.bmWidth, extraH);
FillRect(hdcDest, &rc, br);
// copy original
BitBlt(hdcDest, 0, extraH, bmp.bmWidth, bmp.bmHeight, hdcSrc, 0,0, SRCCOPY);
// draw number
SetTextColor(hdcDest, RGB(80, 60, 10));
SetBkMode(hdcDest, TRANSPARENT);
SetRect(&rc, bmp.bmWidth + 6, rc.top -= 22, bmp.bmWidth + extraW, bmp.bmHeight + extraH);
DrawText(hdcDest, ver, -1, &rc, DT_RIGHT |DT_SINGLELINE);
DeleteObject(fnt);
DeleteObject(br);
DeleteObject(hbmp);
DeleteDC(hdcSrc);
DeleteDC(hdcDest);
ReleaseDC(NULL, hdcWnd);
hbmp = hbmpNew;
}
return hbmp;
}
#endif
+37
View File
@@ -0,0 +1,37 @@
#ifndef NULLSOFT_IN_MP3_ADTS_H
#define NULLSOFT_IN_MP3_ADTS_H
#include "ifc_mpeg_stream_reader.h"
#include <bfc/std_mkncc.h> // for MKnCC()
class adts
{
protected:
adts() {}
~adts() {}
public:
static FOURCC getServiceType() { return MK4CC('a','d','t','s'); }
virtual int Initialize(bool forceMono, bool reverseStereo, bool allowSurround, int maxBits, bool allowRG, bool _useFloat = false, bool _useCRC = false)=0;
virtual bool Open(ifc_mpeg_stream_reader *file)=0;
virtual int Sync(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate)=0;
virtual void CalculateFrameSize(int *frameSize)=0;
virtual void GetOutputParameters(size_t *numBits, int *numChannels, int *sampleRate)=0;
virtual void Flush(ifc_mpeg_stream_reader *file)=0;
virtual void Close() = 0;
enum
{
SUCCESS = 0,
FAILURE=1,
ENDOFFILE = 2,
NEEDMOREDATA = 3,
NEEDSYNC = 4,
};
virtual int Decode(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate, size_t *endCut)=0;
virtual size_t GetCurrentBitrate()=0;
virtual size_t GetDecoderDelay()=0;
virtual int GetLayer()=0;
virtual void Release()=0;
virtual void SetDecoderHooks(void *layer3_vis, void *layer2_eq, void *layer3_eq) {}
};
#endif
+400
View File
@@ -0,0 +1,400 @@
#include "main.h"
#include "adts_mp2.h"
#include "../winamp/wa_ipc.h"
#include <math.h>
#include "mpegutil.h"
#include "../nsutil/pcm.h"
extern int g_ds;
<<<<<<< HEAD:in_mp3/adts_mp2.cpp
DecoderHooks hooks={mp3GiveVisData, mp2Equalize, mp3Equalize};
=======
>>>>>>> 5058463... fix old-school vis/eq mp3 stuff:mp3/adts_mp2.cpp
ADTS_MP2::ADTS_MP2() : decoder(0), gain(1.f)
{
memset(&hooks, 0, sizeof(hooks));
#ifndef NO_MP3SURROUND
lineFilled=false;
saDecHandle=0;
saMode = SA_DEC_OFF;
#endif
decoderDelay = 529;
endcut=0;
outputFrameSize = 0;
bitsPerSample = 0;
allowRG = false;
useFloat = false;
channels = 0;
sampleRate = 0;
memset(&delayline, 0, sizeof(delayline));
delaylineSize = 0;
}
void ADTS_MP2::SetDecoderHooks(void *layer3_vis, void *layer2_eq, void *layer3_eq)
{
<<<<<<< HEAD:in_mp3/adts_mp2.cpp
//*(void **)&hooks.layer3_vis = layer3_vis;
=======
*(void **)&hooks.layer3_vis = layer3_vis;
>>>>>>> 5058463... fix old-school vis/eq mp3 stuff:mp3/adts_mp2.cpp
*(void **)&hooks.layer2_eq = layer2_eq;
*(void **)&hooks.layer3_eq = layer3_eq;
}
int ADTS_MP2::Initialize(bool forceMono, bool reverseStereo, bool allowSurround, int maxBits, bool _allowRG, bool _useFloat, bool _useCRC)
{
allowRG = _allowRG;
useFloat = _useFloat;
int downmix = 0;
if (reverseStereo)
downmix = 2;
else
downmix = forceMono ? 1 : 0;
bitsPerSample = maxBits;
<<<<<<< HEAD:in_mp3/adts_mp2.cpp
decoder = new CMpgaDecoder(&hooks, g_ds, downmix, !!_useCRC);
=======
decoder = new CMpgaDecoder(hooks.layer3_vis?&hooks:(DecoderHooks *)0, MPEGAUDIO_QUALITY_FULL/*g_ds*/, downmix, _useCRC);
>>>>>>> 5058463... fix old-school vis/eq mp3 stuff:mp3/adts_mp2.cpp
#ifndef NO_MP3SURROUND
if (allowSurround)
IIS_SADec_Init(&saDecHandle, 6);
#endif
return 0;
}
bool ADTS_MP2::Open(ifc_mpeg_stream_reader *file)
{
decoder->Connect((CGioFile *)file);
if (allowRG)
gain = file->MPEGStream_Gain();
return true;
}
void ADTS_MP2::Close()
{
if (decoder)
{
delete decoder;
decoder = 0;
}
#ifndef NO_MP3SURROUND
if (saDecHandle)
IIS_SADec_Free(&saDecHandle);
saDecHandle=0;
#endif
}
void ADTS_MP2::GetOutputParameters(size_t *numBits, int *numChannels, int *sampleRate)
{
*sampleRate = this->sampleRate;
*numChannels = channels;
*numBits = bitsPerSample;
}
void ADTS_MP2::CalculateFrameSize(int *frameSize)
{
*frameSize = outputFrameSize;
if (decoder->GetStreamInfo()->GetLayer() == 1)
*frameSize *= 3;
}
void ADTS_MP2::Flush(ifc_mpeg_stream_reader *file)
{
decoder->Reset();
#ifndef NO_MP3SURROUND
if (saDecHandle)
IIS_SADec_Reset(saDecHandle);
lineFilled=false;
#endif
}
size_t ADTS_MP2::GetCurrentBitrate()
{
return decoder->GetStreamInfo()->GetBitrate() / 1000;
}
size_t ADTS_MP2::GetDecoderDelay()
{
#ifndef NO_MP3SURROUND
if (!saDecHandle || saMode == SA_DEC_OFF || saMode == SA_DEC_BYPASS)
return decoderDelay;
else /* bcc adds 576 delay */
return decoderDelay+576;
#else
return decoderDelay;
#endif
}
static void Decimate(const float *input, void *output, size_t numSamples, size_t *outputWritten, int bitsPerSample, bool useFloat, float gain)
{
if (!useFloat)
{
// TODO seen a few crashes reported where 'output' is 0
nsutil_pcm_FloatToInt_Interleaved_Gain(output, input, bitsPerSample, numSamples, gain);
}
else if (gain != 1.f)
{
float *data = (float *)output;
for (size_t i=0;i<numSamples;i++)
data[i]*=gain;
//data[i]=input[i]*gain;
}
*outputWritten = numSamples * (bitsPerSample / 8);
}
/*
notes for mp3 surround implementations
need to check the first two frames for ancillary data
store first valid in temp
store second valid frame in delay line
decimate first valid into output buffer
ancillary data is stored one frame behind, so PCM data decoded from mp3 frame n combines with anc data from frame n+1
*/
int ADTS_MP2::Sync(ifc_mpeg_stream_reader *_file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate)
{
SSC ssc;
CGioFile *file = (CGioFile *)_file;
unsigned char ancBytes[8192] = {0};
int numAncBytes = 0;
unsigned int delay=0, totalLength=0;
float floatTemp[1152*2] = {0};
float *flData=useFloat?(float *)output:floatTemp;
ssc = decoder->DecodeFrame(flData, sizeof(floatTemp), &outputFrameSize,
<<<<<<< HEAD:in_mp3/adts_mp2.cpp
ancBytes, &numAncBytes, 1, &delay, &totalLength);
// TODO: benski> we should really have CGioFile try to read this stuff
if (delay && !file->prepad)
{
// validate
if (delay >= 529)
{
decoderDelay = delay;
endcut = 1152 - ((totalLength + delay) % 1152); // how many 0 samples had to be added?
endcut += decoderDelay; // also need to cut out the encoder+decoder delay
file->m_vbr_samples = totalLength;
}
}
=======
ancBytes, &numAncBytes);
>>>>>>> fd5c493... have CGioFile read the OFL (from newer fraunhofer encoders):mp3/adts_mp2.cpp
switch (ssc)
{
case SSC_OK:
{
channels = decoder->GetStreamInfo()->GetEffectiveChannels();
sampleRate = decoder->GetStreamInfo()->GetEffectiveSFreq();
#ifndef NO_MP3SURROUND
if (!numAncBytes && saDecHandle)
{
ssc = decoder->DecodeFrame(delayline, sizeof(delayline), &delaylineSize,
ancBytes, &numAncBytes);
if (SSC_SUCCESS(ssc))
{
lineFilled=true;
}
else if (ssc == SSC_W_MPGA_SYNCEOF)
return ENDOFFILE;
else
return NEEDMOREDATA;
}
if (saDecHandle)
{
SA_DEC_ERROR sa_error = IIS_SADec_DecodeAncData(saDecHandle, ancBytes, numAncBytes, 0, 0);
if (sa_error == SA_DEC_NO_ERROR)
{
IIS_SADec_InitInfo(saDecHandle, sampleRate, channels);
SA_DEC_INFO saInfo = IIS_SADec_GetInfo(saDecHandle);
sampleRate = saInfo.SampleRate;
channels = saInfo.nChannelsOut;
saMode = saInfo.configuredMode;
}
else if (saMode == SA_DEC_OFF)
{
IIS_SADec_Free(&saDecHandle);
saDecHandle=0;
}
else
{
lineFilled=false;
return NEEDMOREDATA;
}
}
if (saDecHandle)
{
float surroundFloatTemp[1152*6] = {0};
int outputSamples = 0;
/*SA_DEC_ERROR sa_error = */IIS_SADec_DecodeFrame(saDecHandle,
flData, outputFrameSize/sizeof(float),
(char *)ancBytes, numAncBytes,
surroundFloatTemp, sizeof(surroundFloatTemp),
&outputSamples, saMode, 0, 0,
0, 0);
if (useFloat)
memcpy(output, surroundFloatTemp, sizeof(surroundFloatTemp));
Decimate(surroundFloatTemp, output, outputSamples, outputWritten, bitsPerSample, useFloat, (float)gain);
outputFrameSize = *outputWritten;
}
else
#endif
{
Decimate(floatTemp, output, outputFrameSize / sizeof(float), outputWritten, bitsPerSample, useFloat, (float)gain);
outputFrameSize = *outputWritten;
}
}
return SSC_OK;
case SSC_W_MPGA_SYNCSEARCHED:
return NEEDMOREDATA;
case SSC_W_MPGA_SYNCEOF:
return ENDOFFILE;
case SSC_E_MPGA_WRONGLAYER:
decoder->m_Mbs.Seek(1);
default:
return NEEDMOREDATA;
}
}
int ADTS_MP2::Decode(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate, size_t *endCut)
{
if (endcut)
{
*endCut = endcut;
endcut=0;
}
#ifndef NO_MP3SURROUND
if (!saDecHandle && lineFilled) // if we don't have surround info, go ahead and flush out the delayline buffer
{
Decimate(delayline, output, delaylineSize / sizeof(float), outputWritten, bitsPerSample, useFloat, (float)gain);
*bitrate = decoder->GetStreamInfo()->GetBitrate() / 1000;
lineFilled=false;
return adts::SUCCESS;
}
if (saDecHandle && !lineFilled && !decoder->IsEof()) // have surround info, but don't have a previously decoded frame
{
// resync
int ret = Sync(file, output, outputSize, outputWritten, bitrate);
if (ret == SSC_OK && saDecHandle)
{
*bitrate = decoder->GetStreamInfo()->GetBitrate() / 1000;
return adts::SUCCESS;
}
else if (saDecHandle)
return ret;
else
return adts::FAILURE;
}
#endif
unsigned char ancBytes[8192] = {0};
int numAncBytes = 0;
int newl;
float floatTemp[1152*2] = {0};
float *flData=useFloat?(float *)output:floatTemp;
SSC ssc = decoder->DecodeFrame(flData, sizeof(floatTemp), &newl, ancBytes, &numAncBytes);
if (SSC_SUCCESS(ssc))
{
#ifndef NO_MP3SURROUND
if (saDecHandle && lineFilled)
{
float surroundFloatTemp[1152*6] = {0};
int outputSamples;
/*SA_DEC_ERROR sa_error = */IIS_SADec_DecodeFrame(saDecHandle,
delayline, delaylineSize/sizeof(float),
(char *)ancBytes, numAncBytes,
surroundFloatTemp, sizeof(surroundFloatTemp),
&outputSamples, saMode, 0, 0,
0, 0);
if (useFloat)
memcpy(output, surroundFloatTemp, sizeof(surroundFloatTemp));
Decimate(surroundFloatTemp, output, outputSamples, outputWritten, bitsPerSample, useFloat, (float)gain);
memcpy(delayline, flData, delaylineSize);
}
else
#endif
{
Decimate(floatTemp, output, newl / sizeof(float), outputWritten, bitsPerSample, useFloat, (float)gain);
}
*bitrate = decoder->GetStreamInfo()->GetBitrate() / 1000;
return adts::SUCCESS;
}
else if (decoder->IsEof())
{
#ifndef NO_MP3SURROUND
/* In case of SA processing one ancillary data
package and maybe fill samples left in the dynamic
buffer of the mp3 decoder. Take care, that the
ancillary data buffer is greater then the dynamic buffer of
the mp3 decoder. */
if (saDecHandle && lineFilled)
{
decoder->GetLastAncData(ancBytes, &numAncBytes);
float surroundFloatTemp[1152*6];
int outputSamples = 0;
/*SA_DEC_ERROR sa_error = */IIS_SADec_DecodeFrame(saDecHandle,
delayline, delaylineSize/sizeof(float),
(char *)ancBytes, numAncBytes,
surroundFloatTemp, sizeof(surroundFloatTemp),
&outputSamples, saMode, 0, 0,
0, 0);
if (useFloat)
memcpy(output, surroundFloatTemp, sizeof(surroundFloatTemp));
Decimate(surroundFloatTemp, output, outputSamples, outputWritten, bitsPerSample, useFloat, (float)gain);
lineFilled=false;
*bitrate = decoder->GetStreamInfo()->GetBitrate() / 1000;
return adts::SUCCESS;
}
else
#endif
return adts::ENDOFFILE;
}
else if (ssc == SSC_W_MPGA_SYNCNEEDDATA)
{
*bitrate = decoder->GetStreamInfo()->GetBitrate() / 1000;
return adts::NEEDMOREDATA;
}
else if (ssc==SSC_W_MPGA_SYNCLOST || ssc==SSC_W_MPGA_SYNCSEARCHED)
{
*bitrate = decoder->GetStreamInfo()->GetBitrate() / 1000;
return adts::NEEDSYNC;
}
else
{
if (ssc == SSC_E_MPGA_WRONGLAYER)
decoder->m_Mbs.Seek(1);
return adts::FAILURE;
}
}
int ADTS_MP2::GetLayer()
{
if (decoder)
return decoder->GetStreamInfo()->GetLayer();
else
return 0;
}
void ADTS_MP2::Release()
{
delete this;
}
+58
View File
@@ -0,0 +1,58 @@
#ifndef NULLSOFT_IN_MP3_ADTS_MP2_H
#define NULLSOFT_IN_MP3_ADTS_MP2_H
#include "adts.h"
#include "api.h"
#include "config.h"
#ifndef NO_MP3SURROUND
#include "../mp3/bccDecLinklib/include/bccDecLink.h" // Binaural Cue Coding (aka mp3 surround)
#endif
class ADTS_MP2 : public adts
{
public:
ADTS_MP2();
int Initialize(bool forceMono, bool reverse_stereo, bool allowSurround, int maxBits, bool allowRG, bool _useFloat, bool _useCRC);
bool Open(ifc_mpeg_stream_reader *file);
void Close();
void GetOutputParameters(size_t *numBits, int *numChannels, int *sampleRate);
void CalculateFrameSize(int *frameSize);
void Flush(ifc_mpeg_stream_reader *file);
size_t GetCurrentBitrate();
size_t GetDecoderDelay();
int Sync(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate);
int Decode(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate, size_t *endCut);
int GetLayer();
void Release();
void SetDecoderHooks(void *layer3_vis, void *layer2_eq, void *layer3_eq);
<<<<<<< HEAD:in_mp3/adts_mp2.h
=======
>>>>>>> 5058463... fix old-school vis/eq mp3 stuff:mp3/adts_mp2.h
private:
DecoderHooks hooks;
CMpgaDecoder *decoder;
int outputFrameSize;
size_t bitsPerSample;
double gain;
bool allowRG;
bool useFloat;
int channels;
int sampleRate;
unsigned int decoderDelay;
unsigned int endcut;
#ifndef NO_MP3SURROUND
float delayline[1152*2];
int delaylineSize;
bool lineFilled;
SADEC_HANDLE saDecHandle;
SA_DEC_MODE saMode;
#endif
};
#endif
+153
View File
@@ -0,0 +1,153 @@
#include "adts_vlb.h"
#include "giofile.h"
#include "in2.h"
extern In_Module mod;
ADTS_VLB::ADTS_VLB() : decoder(0), needsync(1)
{}
int ADTS_VLB::Initialize(bool forceMono, bool reverseStereo, bool allowSurround, int maxBits, bool allowRG, bool _useFloat, bool _useCRC)
{
return 0;
}
bool ADTS_VLB::Open(ifc_mpeg_stream_reader *file)
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(obj_vlbDecoderGUID);
if (factory)
decoder = (obj_vlbDecoder *)factory->getInterface();
if (decoder)
{
int status = decoder->Open((DataIOControl *)(CGioFile *)file);
if (status == 0)
return true;
}
return false;
}
void ADTS_VLB::Close()
{
if (decoder)
{
waServiceFactory *factory = mod.service->service_getServiceByGuid(obj_vlbDecoderGUID);
if (factory)
factory->releaseInterface(decoder);
}
decoder = 0;
}
void ADTS_VLB::GetOutputParameters(size_t *numBits, int *numChannels, int *sampleRate)
{
*sampleRate = params.sampling_frequency;
*numChannels = params.num_channels;
*numBits = 16;
}
void ADTS_VLB::CalculateFrameSize( int *frameSize )
{
*frameSize = 576 * 2 * params.num_channels;
if ( *frameSize > 576 * 2 * 2 )
*frameSize = 576 * 2 * 2;
}
void ADTS_VLB::Flush(ifc_mpeg_stream_reader *file)
{
decoder->Flush();
decoder->Close();
decoder->Open((DataIOControl *)(CGioFile *)file);
needsync = 1;
}
size_t ADTS_VLB::GetCurrentBitrate()
{
return params.bitrate / 1000;
}
size_t ADTS_VLB::GetDecoderDelay()
{
return 0; // not really sure
}
int ADTS_VLB::Sync(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate)
{
int status = decoder->Synchronize(&params);
if (!status)
{
needsync = 0;
return SUCCESS;
}
if (file->MPEGStream_EOF())
return ENDOFFILE;
return NEEDMOREDATA;
}
int ADTS_VLB::Decode(ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate, size_t *endCut)
{
if (*outputWritten = decoder->Read(output, outputSize))
{
// TODO: benski> verify that params is valid here
*bitrate = params.bitrate / 1000;
return adts::SUCCESS;
}
if (needsync)
{
int status = decoder->Synchronize(&params);
if (!status)
{
needsync = 0;
}
else if (file->MPEGStream_EOF())
{
return adts::ENDOFFILE;
}
}
if (!needsync)
{
int status = decoder->DecodeFrame(&params);
if (status > ERR_NO_ERROR && status != ERR_END_OF_FILE)
{
needsync = 1;
return adts::FAILURE;
}
else
{
if (status == ERR_END_OF_FILE)
{
if (file->MPEGStream_EOF())
{
return adts::ENDOFFILE;
}
else
{
*bitrate = params.bitrate / 1000;
return adts::NEEDMOREDATA;
}
}
*bitrate = params.bitrate / 1000;
return adts::SUCCESS;
}
}
return adts::SUCCESS;
}
int ADTS_VLB::GetLayer()
{
return 4;
}
void ADTS_VLB::Release()
{
delete this;
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef NULLSOFT_IN_MP3_ADTS_VLB_H
#define NULLSOFT_IN_MP3_ADTS_VLB_H
#include "adts.h"
#include "../vlb/obj_vlbDecoder.h"
#include "api__in_mp3.h"
#include <api/service/waServiceFactory.h>
class ADTS_VLB : public adts
{
public:
ADTS_VLB();
int Initialize( bool forceMono, bool reverseStereo, bool allowSurround, int maxBits, bool allowRG, bool _useFloat, bool _useCRC );
bool Open( ifc_mpeg_stream_reader *file );
void Close();
void GetOutputParameters( size_t *numBits, int *numChannels, int *sampleRate );
void CalculateFrameSize( int *frameSize );
void Flush( ifc_mpeg_stream_reader *file );
size_t GetCurrentBitrate();
size_t GetDecoderDelay();
int Sync( ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate );
int Decode( ifc_mpeg_stream_reader *file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate, size_t *endCut );
int GetLayer();
void Release();
private:
obj_vlbDecoder *decoder;
int needsync;
AACStreamParameters params;
};
#endif
+169
View File
@@ -0,0 +1,169 @@
#include "apev2.h"
APE::APE()
{
hasData=false;
dirty=false;
}
int APE::Decode(const void *data, size_t len)
{
if (APEv2::Tag::Parse(data, len) == APEv2::APEV2_SUCCESS)
{
hasData=true;
return 1;
}
return 0;
}
// return -1 for empty, 1 for OK, 0 for "don't understand metadata name"
int APE::GetString(const char *metadata, wchar_t *data, int dataLen)
{
if (!hasData)
return 0;
if (!_stricmp(metadata, "replaygain_track_gain")
|| !_stricmp(metadata, "replaygain_track_peak")
|| !_stricmp(metadata, "replaygain_album_gain")
|| !_stricmp(metadata, "replaygain_album_peak"))
{
if (APEv2::Tag::GetString(metadata, data, dataLen) == APEv2::APEV2_SUCCESS)
return 1;
return -1;
}
else
{
const char *ape_key = MapWinampKeyToApeKey(metadata);
if (ape_key)
{
if (APEv2::Tag::GetString(ape_key, data, dataLen) == APEv2::APEV2_SUCCESS)
return 1;
return -1;
}
}
return 0;
}
int APE::SetString(const char *metadata, const wchar_t *data)
{
if (!_stricmp(metadata, "replaygain_track_gain")
|| !_stricmp(metadata, "replaygain_track_peak")
|| !_stricmp(metadata, "replaygain_album_gain")
|| !_stricmp(metadata, "replaygain_album_peak"))
{
APEv2::Tag::SetString(metadata, data);
dirty=true;
hasData=true;
return 1;
}
else
{
const char *ape_key = MapWinampKeyToApeKey(metadata);
if (ape_key)
{
APEv2::Tag::SetString(ape_key, data);
dirty=true;
hasData=true;
return 1;
}
}
return 0;
}
void APE::Clear()
{
APEv2::Tag::Clear();
dirty=true;
hasData=false;
}
void APE::MarkClear()
{
dirty=true;
hasData=false;
}
int APE::SetKeyValueByIndex(size_t index, const char *key, const wchar_t *data)
{
dirty=true;
return APEv2::Tag::SetKeyValueByIndex(index, key, data);
}
int APE::RemoveItem(size_t index)
{
dirty=true;
return APEv2::Tag::RemoveItem(index);
}
int APE::AddItem()
{
dirty=true;
hasData=true;
APEv2::Tag::AddItem();
return APEv2::APEV2_SUCCESS;
}
struct ApeKeyMapping
{
const char *ape_key;
const char *winamp_key;
const wchar_t *winamp_keyW;
};
static ApeKeyMapping apeKeyMapping[] =
{
{ "Track", "track", L"track" },
{"Album", "album", L"album" },
{"Artist", "artist", L"artist" },
{"Comment", "comment", L"comment" },
{"Year", "year", L"year" },
{"Genre", "genre", L"genre" },
{"Title", "title", L"title"},
{"Composer", "composer", L"composer"},
{"Performer", "performer", L"performer"},
{"Album artist", "albumartist", L"albumartist"},
};
const wchar_t *APE::MapApeKeyToWinampKeyW(const char *ape_key)
{
size_t num_mappings = sizeof(apeKeyMapping)/sizeof(apeKeyMapping[0]);
for (size_t i=0;i!=num_mappings;i++)
{
if (!_stricmp(ape_key, apeKeyMapping[i].ape_key))
return apeKeyMapping[i].winamp_keyW;
}
return NULL;
}
const char *APE::MapApeKeyToWinampKey(const char *ape_key)
{
size_t num_mappings = sizeof(apeKeyMapping)/sizeof(apeKeyMapping[0]);
for (size_t i=0;i!=num_mappings;i++)
{
if (!_stricmp(ape_key, apeKeyMapping[i].ape_key))
return apeKeyMapping[i].winamp_key;
}
return NULL;
}
const char *APE::MapWinampKeyToApeKey(const char *winamp_key)
{
size_t num_mappings = sizeof(apeKeyMapping)/sizeof(apeKeyMapping[0]);
for (size_t i=0;i!=num_mappings;i++)
{
if (!_stricmp(winamp_key, apeKeyMapping[i].winamp_key))
return apeKeyMapping[i].ape_key;
}
return NULL;
}
int APE::AddKeyValue(const char *key, const wchar_t *data)
{
dirty=true;
hasData=true;
APEv2::Item *newItem = APEv2::Tag::AddItem();
newItem->SetKey(key);
return APEv2::Tag::SetItemData(newItem, data);
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef NULLSOFT_IN_MP3_APEV2_H
#define NULLSOFT_IN_MP3_APEV2_H
#include "../apev2/tag.h"
class APE : private APEv2::Tag
{
public:
APE();
bool HasData() { return hasData; }
bool IsDirty() { return dirty; }
void ResetDirty() { dirty=0; hasData = true; }
void Clear();
void MarkClear();
int Decode(const void *data, size_t len);
// return -1 for empty, 1 for OK, 0 for "don't understand tag name"
int GetString(const char *tag, wchar_t *data, int dataLen);
int SetString(const char *tag, const wchar_t *data);
int AddKeyValue(const char *key, const wchar_t *data);
int SetKeyValueByIndex(size_t index, const char *key, const wchar_t *data);
int RemoveItem(size_t index);
int AddItem();
static const char *MapApeKeyToWinampKey(const char *ape_key);
static const wchar_t *MapApeKeyToWinampKeyW(const char *ape_key);
static const char *MapWinampKeyToApeKey(const char *winamp_key);
using APEv2::Tag::EnumValue;
using APEv2::Tag::EncodeSize;
using APEv2::Tag::Encode;
using APEv2::Tag::FindItemByKey;
using APEv2::Tag::GetNumItems;
using APEv2::Tag::IsItemReadOnly;
using APEv2::Tag::SetFlags;
private:
bool hasData;
bool dirty;
};
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef NULLSOFT_IN_MP3_API_H
#define NULLSOFT_IN_MP3_API_H
#include "../Agave/Config/api_config.h"
#include "api/memmgr/api_memmgr.h"
extern api_memmgr *memmgr;
#define WASABI_API_MEMMGR memmgr
#include "../Agave/Language/api_language.h"
#include "api/application/api_application.h"
extern api_application *applicationApi;
#define WASABI_API_APP applicationApi
#endif // !NULLSOFT_IN_MP3_API_H
+685
View File
@@ -0,0 +1,685 @@
#include "main.h"
#include <shlobj.h>
#include <commctrl.h>
#include <windows.h>
#include "../winamp/wa_ipc.h"
#include "config.h"
#include "api__in_mp3.h"
#include "resource.h"
char g_http_tmp[MAX_PATH] = {0};
int config_write_mode = WRITE_UTF16;
int config_read_mode = READ_LOCAL;
int config_parse_apev2 = 1;
int config_parse_lyrics3 = 1;
int config_parse_id3v1 = 1;
int config_parse_id3v2 = 1;
int config_write_apev2 = 1;
int config_write_id3v1 = 1;
int config_write_id3v2 = 1;
int config_create_id3v1 = 1;
int config_create_id3v2 = 1;
int config_create_apev2 = 0;
int config_apev2_header = RETAIN_HEADER;
int config_lp = 0;
BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
{
wchar_t cl[32] = {0};
GetClassNameW(hwnd, cl, ARRAYSIZE(cl));
if (!lstrcmpiW(cl, WC_TREEVIEW))
{
PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
return FALSE;
}
return TRUE;
}
static int CALLBACK BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
switch (uMsg)
{
case BFFM_INITIALIZED:
{
SetWindowText(hwnd, WASABI_API_LNGSTRINGW(IDS_SELECT_DIRECTORY_TO_SAVE_TO));
if (g_http_tmp[0]) SendMessage(hwnd, BFFM_SETSELECTIONA, 1, (LPARAM)g_http_tmp);
// this is not nice but it fixes the selection not working correctly on all OSes
EnumChildWindows(hwnd, browseEnumProc, 0);
}
}
return 0;
}
static char app_name[] = "Nullsoft MPEG Decoder";
char *get_inifile() { return INI_FILE; }
int _r_i(char *name, int def)
{
if (!_strnicmp(name, "config_", 7)) name += 7;
return GetPrivateProfileIntA(app_name, name, def, INI_FILE);
}
#define RI(x) (( x ) = _r_i(#x,( x )))
void _w_i(char *name, int d)
{
char str[120] = {0};
wsprintfA(str, "%d", d);
if (!_strnicmp(name, "config_", 7)) name += 7;
WritePrivateProfileStringA(app_name, name, str, INI_FILE);
}
#define WI(x) _w_i(#x,( x ))
void _r_s(char *name, char *data, int mlen)
{
char buf[2048] = {0};
lstrcpynA(buf, data, 2048);
if (!_strnicmp(name, "config_", 7)) name += 7;
GetPrivateProfileStringA(app_name, name, buf, data, mlen, INI_FILE);
}
#define RS(x) (_r_s(#x,x,sizeof(x)))
void _w_s(char *name, char *data)
{
if (!_strnicmp(name, "config_", 7)) name += 7;
WritePrivateProfileStringA(app_name, name, data, INI_FILE);
}
#define WS(x) (_w_s(#x,x))
static void config_init()
{
char *p;
if (mod.hMainWindow &&
(p = (char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))
&& p != (char *)1)
{
strncpy(INI_FILE, p, MAX_PATH);
}
else
{
GetModuleFileNameA(NULL, INI_FILE, sizeof(INI_FILE));
p = INI_FILE + strlen(INI_FILE);
while (p >= INI_FILE && *p != '.') p--;
strcpy(++p, "ini");
}
}
#ifdef AAC_SUPPORT
#define DEF_EXT_LIST "MP3;MP2;MP1;AAC;VLB"
#else
#define DEF_EXT_LIST "MP3;MP2;MP1"
#endif
#define __STR2WSTR(str) L##str
#define WIDEN(str) __STR2WSTR(str)
#define DEF_EXT_LISTW WIDEN(DEF_EXT_LIST)
#ifdef AAC_SUPPORT
char config_extlist_aac[129] = DEF_EXT_LIST;
#else
char config_extlist[129] = DEF_EXT_LIST;
#endif
char config_rating_email[255] = {0};
void config_read()
{
config_init();
RI(allow_scartwork);
RI(allow_sctitles);
RI(sctitle_format);
RI(config_http_buffersize);
RI(config_http_prebuffer);
RI(config_http_prebuffer_underrun);
RI(config_downmix);
RI(config_downsample);
RI(config_max_bufsize_k);
RI(config_eqmode);
RI(config_gapless);
if(FAILED(SHGetFolderPathA(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, config_http_save_dir)))
{
if(FAILED(SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, config_http_save_dir)))
{
lstrcpynA(config_http_save_dir, "C:\\", MAX_PATH);
}
}
RS(config_http_save_dir);
RI(config_miscopts);
RI(config_fastvis);
#ifdef AAC_SUPPORT
RS(config_extlist_aac);
#else
RS(config_extlist);
#endif
RI(config_write_mode);
RI(config_read_mode);
RI(config_parse_apev2);
RI(config_parse_lyrics3);
RI(config_parse_id3v1);
RI(config_parse_id3v2);
RI(config_write_apev2);
RI(config_write_id3v1);
RI(config_write_id3v2);
RI(config_create_apev2);
RI(config_create_id3v1);
RI(config_create_id3v2);
RI(config_apev2_header);
RI(config_lp);
RS(config_rating_email);
}
void config_write()
{
WI(allow_scartwork);
WI(config_fastvis);
WI(config_miscopts);
WI(allow_sctitles);
WI(sctitle_format);
WI(config_http_buffersize);
WI(config_http_buffersize);
WI(config_http_prebuffer);
WI(config_http_prebuffer_underrun);
WI(config_downmix);
WI(config_downsample);
WI(config_max_bufsize_k);
WI(config_eqmode);
WS(config_http_save_dir);
#ifdef AAC_SUPPORT
WS(config_extlist_aac);
#else
WS(config_extlist);
#endif
WI(config_write_mode);
WI(config_read_mode);
WI(config_parse_apev2);
WI(config_parse_lyrics3);
WI(config_parse_id3v1);
WI(config_parse_id3v2);
WI(config_write_apev2);
WI(config_write_id3v1);
WI(config_write_id3v2);
WI(config_create_apev2);
WI(config_create_id3v1);
WI(config_create_id3v2);
WI(config_apev2_header);
WI(config_lp);
WS(config_rating_email);
}
static INT_PTR CALLBACK prefsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK id3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK advancedTaggingProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK httpProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK outputProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
#define ISSEP(x) ((x) == ' ' || (x) == ';' || (x) == ',' || (x) == ':' || (x) == '.')
char *getfileextensions()
{
static char list[512];
char *op = list;
// char *g_fileassos="MP3;MP2;MP1\0MPEG Audio Files (*.MP3;*.MP2;*.MP1)\0";
char *p = config_extlist;
int s = 0;
while (p && *p)
{
while (ISSEP(*p)) p++;
if (!p || !*p) break;
if (s) *op++ = ';';
s = 1;
while (p && *p && !ISSEP(*p)) *op++ = *p++;
}
*op++ = 0;
strcpy(op, WASABI_API_LNGSTRING(IDS_MPEG_AUDIO_FILES));
while (op && *op) op++;
p = config_extlist;
s = 0;
while (p && *p)
{
while (ISSEP(*p)) p++;
if (!p || !*p) break;
if (s) *op++ = ';';
s = 1;
*op++ = '*';
*op++ = '.';
while (p && *p && !ISSEP(*p)) *op++ = *p++;
}
*op++ = ')';
*op++ = 0;
*op++ = 0;
return list;
}
void config(HWND hwndParent)
{
wchar_t title[128] = {0};
int x;
PROPSHEETHEADER pshead;
PROPSHEETPAGE pspage[5];
ZeroMemory(&pshead, sizeof(PROPSHEETHEADER));
pshead.dwSize = sizeof(PROPSHEETHEADER);
pshead.hwndParent = hwndParent;
pshead.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_NOCONTEXTHELP;
pshead.hInstance = WASABI_API_LNG_HINST;
pshead.pszCaption = WASABI_API_LNGSTRINGW_BUF(IDS_MPEG_AUDIO_DECODER_SETTINGS,title,128);//"MPEG Audio Decoder Settings";
pshead.nPages = sizeof(pspage) / sizeof(pspage[0]);
pshead.nStartPage = config_lp;
pshead.ppsp = pspage;
ZeroMemory(pspage, sizeof(pspage));
for ( x = 0; x < sizeof(pspage) / sizeof(pspage[0]); x ++)
pspage[x].dwSize = sizeof(PROPSHEETPAGE);
for ( x = 0; x < sizeof(pspage) / sizeof(pspage[0]); x ++)
pspage[x].hInstance = WASABI_API_LNG_HINST;
pspage[0].pszTemplate = MAKEINTRESOURCE(IDD_PREFS);
pspage[1].pszTemplate = MAKEINTRESOURCE(IDD_TAGOPTS);
pspage[2].pszTemplate = MAKEINTRESOURCE(IDD_ADVANCED_TAGGING);
pspage[3].pszTemplate = MAKEINTRESOURCE(IDD_OUTPUT);
pspage[4].pszTemplate = MAKEINTRESOURCE(IDD_HTTP);
pspage[0].pfnDlgProc = prefsProc;
pspage[1].pfnDlgProc = id3Proc;
pspage[2].pfnDlgProc = advancedTaggingProc;
pspage[3].pfnDlgProc = outputProc;
pspage[4].pfnDlgProc = httpProc;
PropertySheet((PROPSHEETHEADER*)&pshead);
config_write();
extern char *g_fileassos;
mod.FileExtensions = getfileextensions();
}
static INT_PTR CALLBACK id3Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
if (config_parse_id3v1) CheckDlgButton(hwndDlg, IDC_READ_ID3V1, BST_CHECKED);
if (config_parse_id3v2) CheckDlgButton(hwndDlg, IDC_READ_ID3V2, BST_CHECKED);
if (config_write_id3v1) CheckDlgButton(hwndDlg, IDC_WRITE_ID3V1, BST_CHECKED);
if (config_write_id3v2) CheckDlgButton(hwndDlg, IDC_WRITE_ID3V2, BST_CHECKED);
if (config_create_id3v1) CheckDlgButton(hwndDlg, IDC_CREATE_ID3V1, BST_CHECKED);
if (config_create_id3v2) CheckDlgButton(hwndDlg, IDC_CREATE_ID3V2, BST_CHECKED);
SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_LATIN_1));
SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_SYSTEM_LANGUAGE));
SendDlgItemMessage(hwndDlg,IDC_COMBO1,CB_SETCURSEL,(config_read_mode == READ_LOCAL),0);
SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_UNICODE_UTF_16));
SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_LATIN_1));
SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_SYSTEM_LANGUAGE));
SendDlgItemMessage(hwndDlg,IDC_COMBO2,CB_SETCURSEL,config_write_mode,0);
SetDlgItemTextA(hwndDlg,IDC_RATING_EMAIL,(config_rating_email[0] ? config_rating_email : "rating@winamp.com\0"));
return FALSE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR) lParam;
if (pnmh->code == PSN_SETACTIVE)
{
config_lp = 1;
}
if (pnmh->code == PSN_APPLY)
{
config_parse_id3v1 = IsDlgButtonChecked(hwndDlg, IDC_READ_ID3V1);
config_parse_id3v2 = IsDlgButtonChecked(hwndDlg, IDC_READ_ID3V2);
config_write_id3v1 = IsDlgButtonChecked(hwndDlg, IDC_WRITE_ID3V1);
config_write_id3v2 = IsDlgButtonChecked(hwndDlg, IDC_WRITE_ID3V2);
config_create_id3v1 = IsDlgButtonChecked(hwndDlg, IDC_CREATE_ID3V1);
config_create_id3v2 = IsDlgButtonChecked(hwndDlg, IDC_CREATE_ID3V2);
GetDlgItemTextA(hwndDlg,IDC_RATING_EMAIL,config_rating_email,sizeof(config_rating_email));
if (!stricmp(config_rating_email, "rating@winamp.com\0")) config_rating_email[0] = 0;
return TRUE;
}
}
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_COMBO1:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
int cur = (int)SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
if(!cur) config_read_mode = READ_LATIN;
else if(cur == 1) config_read_mode = READ_LOCAL;
}
break;
case IDC_COMBO2:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
int cur = (int)SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
if(!cur) config_write_mode = WRITE_UTF16;
else if(cur == 1) config_write_mode = WRITE_LATIN;
else if(cur == 2) config_write_mode = WRITE_LOCAL;
}
break;
case IDC_RATING_EMAIL_RESET:
if(HIWORD(wParam) == BN_CLICKED)
{
config_rating_email[0] = 0;
SetDlgItemTextA(hwndDlg,IDC_RATING_EMAIL,(config_rating_email[0] ? config_rating_email : "rating@winamp.com\0"));
}
}
return FALSE;
}
return FALSE;
}
static INT_PTR CALLBACK advancedTaggingProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
if (config_parse_apev2) CheckDlgButton(hwndDlg, IDC_READ_APEV2, BST_CHECKED);
if (config_write_apev2) CheckDlgButton(hwndDlg, IDC_WRITE_APEV2, BST_CHECKED);
if (config_create_apev2) CheckDlgButton(hwndDlg, IDC_CREATE_APEV2, BST_CHECKED);
if (config_parse_lyrics3) CheckDlgButton(hwndDlg, IDC_READ_LYRICS3, BST_CHECKED);
SendDlgItemMessage(hwndDlg,IDC_APEV2_HEADER_OPTIONS,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_APEV2_RETAIN_HEADER));
SendDlgItemMessage(hwndDlg,IDC_APEV2_HEADER_OPTIONS,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_APEV2_ADD_HEADER));
SendDlgItemMessage(hwndDlg,IDC_APEV2_HEADER_OPTIONS,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_APEV2_REMOVE_HEADER));
SendDlgItemMessage(hwndDlg,IDC_APEV2_HEADER_OPTIONS,CB_SETCURSEL,config_apev2_header, 0);
return FALSE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR) lParam;
if (pnmh->code == PSN_SETACTIVE)
{
config_lp = 2;
}
if (pnmh->code == PSN_APPLY)
{
config_parse_apev2 = IsDlgButtonChecked(hwndDlg, IDC_READ_APEV2);
config_write_apev2 = IsDlgButtonChecked(hwndDlg, IDC_WRITE_APEV2);
config_create_apev2 = IsDlgButtonChecked(hwndDlg, IDC_CREATE_APEV2);
config_parse_lyrics3 = IsDlgButtonChecked(hwndDlg, IDC_READ_LYRICS3);
return TRUE;
}
}
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_APEV2_HEADER_OPTIONS:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
int cur = (int)SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
if(!cur) config_apev2_header = RETAIN_HEADER;
else if(cur == 1) config_apev2_header = ADD_HEADER;
else if(cur == 2) config_apev2_header = REMOVE_HEADER;
}
break;
}
return FALSE;
}
return FALSE;
}
static INT_PTR CALLBACK prefsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
SetDlgItemTextA(hwndDlg, IDC_EDIT1, config_extlist);
SendDlgItemMessage(hwndDlg, IDC_EDIT1, EM_LIMITTEXT, 128, 0);
{
wchar_t str[10] = L"";
wsprintf(str, L"%d", config_max_bufsize_k);
SetDlgItemText(hwndDlg, IDC_BUFMAX, str);
SendMessage(GetDlgItem(hwndDlg, IDC_BUFMAX), EM_LIMITTEXT, 5, 0);
}
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_BUTTON1:
SetDlgItemText(hwndDlg, IDC_EDIT1, DEF_EXT_LISTW);
break;
}
return FALSE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR) lParam;
if (pnmh->code == PSN_SETACTIVE)
{
config_lp = 0;
}
if (pnmh->code == PSN_APPLY)
{
config_max_bufsize_k = GetDlgItemInt(hwndDlg, IDC_BUFMAX, NULL, 0);
GetDlgItemTextA(hwndDlg, IDC_EDIT1, config_extlist, 128);
return TRUE;
}
}
return FALSE;
}
return FALSE;
}
static INT_PTR CALLBACK outputProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
if (config_eqmode&1) CheckDlgButton(hwndDlg, IDC_RADIO2, 1);
else CheckDlgButton(hwndDlg, IDC_RADIO1, 1);
if (!(config_eqmode&4)) CheckDlgButton(hwndDlg, IDC_FASTL3EQ, 1);
if (config_eqmode&8) CheckDlgButton(hwndDlg, IDC_FASTL12EQ, 1);
if (config_miscopts&1) CheckDlgButton(hwndDlg, IDC_CHECK1, BST_CHECKED);
if (config_miscopts&2) CheckDlgButton(hwndDlg, IDC_CHECK2, BST_CHECKED);
if (config_downmix == 2) CheckDlgButton(hwndDlg, IDC_REVSTEREO, BST_CHECKED);
if (config_downsample == 1)
CheckDlgButton(hwndDlg, IDC_HALFRATE, BST_CHECKED);
else if (config_downsample == 2)
CheckDlgButton(hwndDlg, IDC_QRATE, BST_CHECKED);
else
CheckDlgButton(hwndDlg, IDC_FULLRATE, BST_CHECKED);
return FALSE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR) lParam;
if (pnmh->code == PSN_SETACTIVE)
{
config_lp = 3;
}
if (pnmh->code == PSN_APPLY)
{
config_miscopts &= ~3;
config_miscopts |= IsDlgButtonChecked(hwndDlg, IDC_CHECK1) ? 1 : 0;
config_miscopts |= IsDlgButtonChecked(hwndDlg, IDC_CHECK2) ? 2 : 0;
config_eqmode = IsDlgButtonChecked(hwndDlg, IDC_RADIO1) ? 0 : 1;
config_eqmode |= IsDlgButtonChecked(hwndDlg, IDC_FASTL3EQ) ? 0 : 4;
config_eqmode |= IsDlgButtonChecked(hwndDlg, IDC_FASTL12EQ) ? 8 : 0;
config_downmix = IsDlgButtonChecked(hwndDlg, IDC_REVSTEREO) ? 2 : 0;
config_downsample = IsDlgButtonChecked(hwndDlg, IDC_HALFRATE) ? 1 : 0;
config_downsample = IsDlgButtonChecked(hwndDlg, IDC_QRATE) ? 2 : config_downsample;
return TRUE;
}
}
return FALSE;
}
return FALSE;
}
void SetHTTPSaveButtonText(HWND hwndDlg, char* path)
{
HWND control = GetDlgItem(hwndDlg, IDC_BUTTON2);
HDC hdc = GetDC(control);
RECT r = {0};
char temp[MAX_PATH] = {0};
lstrcpynA(temp, path, MAX_PATH);
SelectObject(hdc, (HFONT)SendMessage(control, WM_GETFONT, 0, 0));
GetClientRect(control, &r);
r.left += 5;
r.right -= 5;
DrawTextA(hdc, temp, -1, &r, DT_PATH_ELLIPSIS|DT_WORD_ELLIPSIS|DT_MODIFYSTRING);
SetWindowTextA(control, temp);
ReleaseDC(control, hdc);
}
static INT_PTR CALLBACK httpProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_CHECK2:
EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON2), IsDlgButtonChecked(hwndDlg, IDC_CHECK2));
break;
case IDC_BUTTON2:
{
BROWSEINFO bi = {0};
wchar_t name[MAX_PATH] = {0};
bi.hwndOwner = hwndDlg;
bi.pszDisplayName = name;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
bi.lpfn = BrowseCallbackProc;
LPITEMIDLIST idlist = SHBrowseForFolder(&bi);
if (idlist)
{
SHGetPathFromIDListA(idlist, g_http_tmp);
IMalloc *m = 0;
SHGetMalloc(&m);
m->Free(idlist);
SetHTTPSaveButtonText(hwndDlg, g_http_tmp);
}
}
return 0;
}
return 0;
case WM_INITDIALOG:
SetDlgItemInt(hwndDlg, IDC_BUFFERS_NUMBUFS, config_http_buffersize, 0);
SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER), TBM_SETRANGEMAX, 0, 50);
SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER), TBM_SETRANGEMIN, 0, 0);
SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER), TBM_SETPOS, 1, config_http_prebuffer / 2);
SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER2), TBM_SETRANGEMAX, 0, 50);
SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER2), TBM_SETRANGEMIN, 0, 0);
SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER2), TBM_SETPOS, 1, config_http_prebuffer_underrun / 2);
CheckDlgButton(hwndDlg, IDC_CHECK1, allow_sctitles);
CheckDlgButton(hwndDlg, IDC_SC_ARTWORK, allow_scartwork);
CheckDlgButton(hwndDlg, IDC_CHECK3, sctitle_format);
if (config_miscopts&16)
{
CheckDlgButton(hwndDlg, IDC_CHECK2, BST_CHECKED);
}
EnableWindow(GetDlgItem(hwndDlg, IDC_BUTTON2), (config_miscopts&16));
SetHTTPSaveButtonText(hwndDlg, config_http_save_dir);
lstrcpynA(g_http_tmp, config_http_save_dir, MAX_PATH);
return FALSE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR) lParam;
if (pnmh->code == PSN_SETACTIVE)
{
config_lp = 4;
}
if (pnmh->code == PSN_APPLY)
{
sctitle_format = !!IsDlgButtonChecked(hwndDlg, IDC_CHECK3);
allow_sctitles = !!IsDlgButtonChecked(hwndDlg, IDC_CHECK1);
allow_scartwork = !!IsDlgButtonChecked(hwndDlg, IDC_SC_ARTWORK);
{
int s;
int t;
t = GetDlgItemInt(hwndDlg, IDC_BUFFERS_NUMBUFS, &s, 0);
if (s) config_http_buffersize = t;
if (config_http_buffersize < 16) config_http_buffersize = 16;
}
config_http_prebuffer = (int)SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER), TBM_GETPOS, 0, 0) * 2;
config_http_prebuffer_underrun = (int)SendMessage(GetDlgItem(hwndDlg, IDC_PREBUFSLIDER2), TBM_GETPOS, 0, 0) * 2;
lstrcpynA(config_http_save_dir, g_http_tmp, MAX_PATH);
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK2))
{
config_miscopts |= 16;
}
else
{
config_miscopts &= ~16;
}
return TRUE;
}
}
return FALSE;
}
const int controls[] =
{
IDC_PREBUFSLIDER,
IDC_PREBUFSLIDER2,
};
if (FALSE != WASABI_API_APP->DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls)))
{
return TRUE;
}
return FALSE;
}
int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
{
MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
msgbx.lpszText = message;
msgbx.lpszCaption = title;
msgbx.lpszIcon = MAKEINTRESOURCE(102);
msgbx.hInstance = GetModuleHandle(0);
msgbx.dwStyle = MB_USERICON;
msgbx.hwndOwner = parent;
return MessageBoxIndirectW(&msgbx);
}
void about(HWND hwndParent)
{
wchar_t message[1024] = {0}, text[1024] = {0};
WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_MPEG_AUDIO_DECODER_OLD,text,1024);
wsprintfW(message, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
mod.description, __DATE__);
DoAboutMessageBox(hwndParent,text,message);
}
+51
View File
@@ -0,0 +1,51 @@
#ifndef NULLSOFT_IN_MP3_CONFIG_H
#define NULLSOFT_IN_MP3_CONFIG_H
#include <bfc/platform/guid.h>
enum
{
WRITE_UTF16 = 0,
WRITE_LATIN = 1,
WRITE_LOCAL = 2,
WRITE_UTF8 = 3,
};
extern int config_write_mode;
enum
{
READ_LATIN = 0,
READ_LOCAL = 1,
};
extern int config_read_mode;
extern int config_parse_apev2;
extern int config_parse_lyrics3;
extern int config_parse_id3v1;
extern int config_parse_id3v2;
extern int config_write_apev2;
extern int config_write_id3v1;
extern int config_write_id3v2;
extern int config_create_id3v1;
extern int config_create_id3v2;
extern int config_create_apev2;
enum
{
RETAIN_HEADER = 0,
ADD_HEADER = 1,
REMOVE_HEADER = 2,
};
extern int config_apev2_header;
extern int config_id3v2_version;
extern int config_lp;
extern char config_rating_email[255];
// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
static const GUID playbackConfigGroupGUID =
{ 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
#endif
File diff suppressed because it is too large Load Diff
+306
View File
@@ -0,0 +1,306 @@
/***************************************************************************\
*
* (C) copyright Fraunhofer - IIS (1998)
* All Rights Reserved
*
* filename: giofile.h
* project : MPEG Decoder
* author : Martin Sieler
* date : 1998-02-11
* contents/description: HEADER - file I/O class for MPEG Decoder
*
*
\***************************************************************************/
#ifndef _GIOFILE_H
#define _GIOFILE_H
/* ------------------------ includes --------------------------------------*/
#include <windows.h>
#include "CVbriHeader.h"
#include "jnetlib/jnetlib.h"
#include "../vlb/dataio.h"
#include "ID3v2.h"
#include "LAMEInfo.h"
#include "../nu/RingBuffer.h"
#include "../apev2/tag.h"
#include "ifc_mpeg_stream_reader.h"
/*-------------------------- defines --------------------------------------*/
/*-------------------------------------------------------------------------*/
class CGioFile : public DataIOControl, public ifc_mpeg_stream_reader
{
public:
CGioFile();
virtual ~CGioFile();
int Open(const wchar_t *pszName, int maxbufsizek);
int Close();
int Read(void *pBuffer, int cbToRead, int *pcbRead);
int Peek(void *pBuffer, int cbToRead, int *pcbRead);
//dataiocontrol interface
int IO(void *buf, int size, int count)
{
int l=0;
Read(buf,count,&l);
return l;
}
int Seek(long offset, int origin)
{
return 0;
}
//int Close() { return 0; }
int EndOf(void)
{
return IsEof();
}
int DICGetLastError()
{
return DATA_IO_ERROR_NONE;
}
int DICGetDirection()
{
return DATA_IO_READ;
}
unsigned int GetAvgVBRBitrate(void)
{
if (m_vbr_ms && m_vbr_frames)
{
if (m_vbr_bytes && encodingMethod != ENCODING_METHOD_CBR)
return (unsigned int)(m_vbr_bytes * 8 / m_vbr_ms);
else
return (unsigned int)(mpeg_length * 8 / m_vbr_ms);
}
return 0;
}
bool IsEof() const;
bool lengthVerified;
bool isSeekReset()
{
if (m_is_stream && m_seek_reset && m_is_stream_seek)
{
m_seek_reset = false;
m_is_stream_seek = false;
return true;
}
else
return false;
}
bool IsStreamSeekable()
{
return m_is_stream_seekable;
}
int GetHeaderOffset();
int PercentAvailable()
{
if (!m_is_stream) return 0;
if (!recvbuffersize) return 0;
if (!m_connection) return 0;
if (constate != 5) return 0;
uint64_t bytes_100 = jnl_connection_receive_bytes_available(m_connection)*100;
bytes_100 /= recvbuffersize;
return (int)bytes_100;
}
int RunStream()
{
if (m_is_stream && m_connection)
{
if (constate != 5) Read(NULL,0,NULL);
else jnl_connection_run(m_connection, -1, -1, NULL, NULL);
int p=jnl_connection_get_state(m_connection);
if (p==JNL_CONNECTION_STATE_ERROR||
p==JNL_CONNECTION_STATE_CLOSED)
return 2;
return 1;
}
return 0;
}
int IsStream()
{
return m_is_stream;
}
void GetStreamInfo(wchar_t *, size_t len);
DWORD GetContentLength(void) const;
DWORD GetCurrentPosition(void) const;
void SetCurrentPosition(long dwPos, int How);
enum { GIO_FILE_BEGIN, GIO_FILE_CURRENT, GIO_FILE_END };
uint64_t mpeg_length; /* length of valid audio data */
uint64_t mpeg_position; /* starting position of first valid decodable non-header MPEG frame */
uint64_t file_position; /* position within the MPEG data that we've read so far */
uint64_t m_vbr_bytes;
int m_vbr_frames, m_vbr_ms;
int encodingMethod;
uint64_t m_vbr_samples;
int prepad, postpad;
void Seek(int posms, int br);
bool IsSeekable();
unsigned char id3v1_data[128];
char stream_url[256];
char stream_name[256];
char stream_genre[256];
char stream_current_title[256];
char *m_content_type;
int uvox_last_message;
char *uvox_3901;
char *uvox_3902;
typedef struct {
char *uvox_stream_artwork;
int uvox_stream_artwork_len;
int uvox_stream_artwork_type;
char *uvox_playing_artwork;
int uvox_playing_artwork_len;
int uvox_playing_artwork_type;
} UVOX_ARTWORK;
UVOX_ARTWORK uvox_artwork;
ID3v2 info;
float GetGain();
unsigned char m_vbr_toc[100];
int m_vbr_frame_len;
int m_vbr_flag;
CVbriHeader *m_vbr_hdr;
FILETIME last_write_time;
void *GetID3v1()
{
if (m_id3v1_len == 128)
return id3v1_data;
else
return 0;
}
void *GetID3v2(uint32_t *len)
{
if (stream_id3v2_buf)
{
*len = stream_id3v2_read;
return stream_id3v2_buf;
}
else
return 0;
}
void *GetLyrics3(uint32_t *len)
{
if (lyrics3_data)
{
*len = lyrics3_size;
return lyrics3_data;
}
else
return 0;
}
void *GetAPEv2(uint32_t *len)
{
if (apev2_data)
{
*len = m_apev2_len;
return apev2_data;
}
return 0;
}
protected:
void ReadiTunesGaps();
private:
/* ID3v2 */
int m_id3v1_len;
/* ID3v2 */
uint32_t stream_id3v2_read;
char *stream_id3v2_buf;
int m_id3v2_len;
/* Lyrics3 */
uint32_t lyrics3_size;
char *lyrics3_data;
/* APEv2 */
uint32_t m_apev2_len;
char *apev2_data;
APEv2::Tag apev2;
int m_is_stream;
jnl_dns_t m_dns;
jnl_connection_t m_connection;
char last_full_url[4096];
int is_stream_seek;
char *host;
char *proxy_host;
char *req;
unsigned short port;
char *lpinfo;
char *proxy_lp;
char *request;
int constate;
char save_filename[256];
char server_name[128];
int recvbuffersize;
int64_t stream_bytes_read;
int64_t stream_metabytes_read;
unsigned int timeout_start;
char force_lpinfo[256];
unsigned char *m_full_buffer;
int is_uvox;
int uvox_stream_data_len;
int uvox_message_cnt, uvox_desyncs;
int uvox_sid,uvox_maxbr, uvox_avgbr,uvox_maxmsg;
unsigned char *uvox_stream_data;
char *uvox_meta[2][32];
int meta_interval,meta_pos;
uint64_t m_full_buffer_pos/*,m_full_buffer_len*/;
char stream_title_save[580];
char last_title_sent[256];
RingBuffer peekBuffer;
//unsigned char m_peekbuf[8192];
//int m_peekbuf_used;
bool no_peek_hack;
int doConnect(const char *str, int start_offset);
void processMetaData(char *data, int lent, int msgId = 0);
int m_redircnt;
int m_auth_tries;
HANDLE hFile;
bool fEof;
char dlg_realm[256];
static INT_PTR CALLBACK httpDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
int m_http_response;
bool m_seek_reset;
bool m_is_stream_seek;
bool m_is_stream_seekable;
bool m_useaproxy;
RECVS_DISPATCH;
};
/*-------------------------------------------------------------------------*/
#endif
@@ -0,0 +1,452 @@
#include ".\filterwater.h"
#include <math.h>
#define random( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))
MLImageFilterWater::MLImageFilterWater(void)
{
hField1 = NULL;
hField2 = NULL;
hHandle = NULL;
width = 0;
height = 0;
drawWithLight = TRUE;
lightModifier = 1;
hPage = 0;
density = 5;
}
MLImageFilterWater::~MLImageFilterWater(void)
{
ClearData();
}
void MLImageFilterWater::ClearData(void)
{
if (hHandle)
{
if (hField1) HeapFree(hHandle, NULL, hField1);
if (hField2) HeapFree(hHandle, NULL, hField2);
HeapDestroy(hHandle);
hField1 = NULL;
hField2 = NULL;
hHandle = NULL;
}
}
BOOL MLImageFilterWater::CreateFor(const MLImage *image)
{
ClearData();
width = image->GetWidth();
height = image->GetHeight();
hPage = 0;
int len = height * width * sizeof(int);
hHandle = HeapCreate(NULL, 3*len, 3*len);
if (!hHandle)
{
width = 0;
height = 0;
return FALSE;
}
hField1 = (int*)HeapAlloc(hHandle, HEAP_ZERO_MEMORY, len);
hField2 = (int*)HeapAlloc(hHandle, HEAP_ZERO_MEMORY, len);
return hField1 && hField2;
}
void MLImageFilterWater::Render(MLImage* destination, const MLImage* source)
{
if(!drawWithLight) DrawWaterNoLight(hPage, destination, source);
else DrawWaterWithLight(destination, source);
CalculateWater(hPage, density);
// CalcWaterBigFilter(hPage, density);
hPage ^= 1;
}
void MLImageFilterWater::CalculateWater(int page, int density)
{
int newh;
int count = width + 1;
int *newptr;
int *oldptr;
if(page == 0)
{
newptr = hField1;
oldptr = hField2;
}
else
{
newptr = hField2;
oldptr = hField1;
}
int x, y;
for (y = (height - 1) * width; count < y; count += 2)
{
for (x = count + width - 2; count < x; count++)
{
// This does the eight-pixel method.
newh = ((oldptr[count + width]
+ oldptr[count - width]
+ oldptr[count + 1]
+ oldptr[count - 1]
+ oldptr[count - width - 1]
+ oldptr[count - width + 1]
+ oldptr[count + width - 1]
+ oldptr[count + width + 1]
) >> 2 )
- newptr[count];
newptr[count] = newh - (newh >> density);
/*
// This is the "sludge" method...
newh = (oldptr[count]<<2)
+ oldptr[count-1-m_iWidth]
+ oldptr[count+1-m_iWidth]
+ oldptr[count-1+m_iWidth]
+ oldptr[count+1+m_iWidth]
+ ((oldptr[count-1]
+ oldptr[count+1]
+ oldptr[count-m_iWidth]
+ oldptr[count+m_iWidth])<<1);
newptr[count] = (newh-(newh>>6)) >> density;
*/
}
}
}
void MLImageFilterWater::SmoothWater(int page)
{
int newh;
int count = width + 1;
int *newptr;
int *oldptr;
if(page == 0)
{
newptr = hField1;
oldptr = hField2;
}
else
{
newptr = hField2;
oldptr = hField1;
}
int x, y;
for(y = 1; y < height; y++, count += 2)
{
for( x = 1; x < width; x++, count++)
{
// This does the eight-pixel method.
newh = ((oldptr[count + width]
+ oldptr[count - width]
+ oldptr[count + 1]
+ oldptr[count - 1]
+ oldptr[count - width - 1]
+ oldptr[count - width + 1]
+ oldptr[count + width - 1]
+ oldptr[count + width + 1]
) >> 3 )
+ newptr[count];
newptr[count] = newh>>1;
}
}
}
void MLImageFilterWater::FlattenWater(void)
{
int len = width * height * sizeof(int);
SecureZeroMemory(hField1, len);
SecureZeroMemory(hField2, len);
}
void MLImageFilterWater::SineBlob(int x, int y, int radius, int height, int page)
{
int cx, cy;
int left,top,right,bottom;
double square, dist;
double radsquare = radius * radius;
double length = double((1024.0/(double)radius)*(1024.0/(double)radius));
int *newptr;
if(page == 0)
{
newptr = hField1;
}
else
{
newptr = hField2;
}
int t = (this->width - 2*radius - 1);
if (t == 0) t = 1;
if(x<0) x = 1 + radius + rand() % t;
t = (this->height - 2*radius - 1);
if (t == 0) t = 1;
if(y<0) y = 1 + radius + rand() % t;
radsquare = (radius*radius);
left = -radius; right = radius;
top = -radius; bottom = radius;
// Perform edge clipping...
if(x - radius < 1) left -= (x-radius-1);
if(y - radius < 1) top -= (y-radius-1);
if(x + radius > this->width - 1) right -= (x + radius - this->width + 1);
if(y + radius > this->height - 1) bottom -= (y + radius - this->height + 1);
for(cy = top; cy < bottom; cy++)
{
for(cx = left; cx < right; cx++)
{
square = cy*cy + cx*cx;
if(square < radsquare)
{
dist = sqrt(square*length);
newptr[this->width*(cy+y) + cx+x] += (int)((cos(dist)+0xffff)*(height)) >> 19;
}
}
}
}
void MLImageFilterWater::WarpBlob(int x, int y, int radius, int height, int page)
{
int cx, cy;
int left,top,right,bottom;
int square;
int radsquare = radius * radius;
int *newptr;
if(page == 0)
{
newptr = hField1;
}
else
{
newptr = hField2;
}
radsquare = (radius*radius);
height /= 64;
left=-radius; right = radius;
top=-radius; bottom = radius;
// Perform edge clipping...
if(x - radius < 1) left -= (x-radius-1);
if(y - radius < 1) top -= (y-radius-1);
if(x + radius > this->width-1) right -= (x+ radius - this->width + 1);
if(y + radius > this->height-1) bottom-= (y + radius - this->height + 1);
for(cy = top; cy < bottom; cy++)
{
for(cx = left; cx < right; cx++)
{
square = cy*cy + cx*cx;
if(square < radsquare)
{
newptr[this->width*(cy+y) + cx+x] += int((radius-sqrt((float)square))*(float)(height));
}
}
}
}
void MLImageFilterWater::HeightBox (int x, int y, int radius, int height, int page)
{
int cx, cy;
int left,top,right,bottom;
int *newptr;
if(page == 0)
{
newptr = hField1;
}
else
{
newptr = hField2;
}
int t = (this->width - 2*radius - 1);
if (t == 0) t = 1;
if(x<0) x = 1 + radius + rand() % t;
t = (this->height - 2*radius - 1);
if (t == 0) t = 1;
if(y<0) y = 1 + radius + rand() % t;
left=-radius; right = radius;
top=-radius; bottom = radius;
// Perform edge clipping...
if(x - radius < 1) left -= (x-radius-1);
if(y - radius < 1) top -= (y-radius-1);
if(x + radius > this->width-1) right -= (x+ radius - this->width + 1);
if(y + radius > this->height-1) bottom-= (y + radius - this->height + 1);
for(cy = top; cy < bottom; cy++)
{
for(cx = left; cx < right; cx++)
{
newptr[this->width*(cy+y) + cx+x] = height;
}
}
}
void MLImageFilterWater::HeightBlob(int x, int y, int radius, int height, int page)
{
int rquad;
int cx, cy;
int left, top, right, bottom;
rquad = radius * radius;
// Make a randomly-placed blob...
int t = (this->width - 2*radius - 1);
if (t == 0) t = 1;
if(x<0) x = 1 + radius + rand() % t;
t = (this->height - 2*radius - 1);
if (t == 0) t = 1;
if(y<0) y = 1 + radius + rand() % t;
left = -radius; right = radius;
top = -radius; bottom = radius;
// Perform edge clipping...
if(x - radius < 1) left -= (x-radius-1);
if(y - radius < 1) top -= (y-radius-1);
if(x + radius > this->width-1) right -= (x+ radius - this->width + 1);
if(y + radius > this->height-1) bottom-= (y + radius - this->height + 1);
for(cy = top; cy < bottom; cy++)
{
int cyq = cy*cy;
for(cx = left; cx < right; cx++)
{
if(cx*cx + cyq < rquad) newptr[this->width * (cy+y) + (cx+x)] += height;
}
}
}
void MLImageFilterWater::CalcWaterBigFilter(int page, int density)
{
int newh;
int count = (2 * width) + 2;
int *newptr;
int *oldptr;
// Set up the pointers
if(page == 0)
{
newptr = hField1;
oldptr = hField2;
}
else
{
newptr = hField2;
oldptr = hField1;
}
int x, y;
for(y=2; y < height-2; y++, count += 4)
{
for(x=2; x < width-2; x++, count++)
{
// This does the 25-pixel method. It looks much okay.
newh = (
(
(
(oldptr[count + width]
+ oldptr[count - width]
+ oldptr[count + 1]
+ oldptr[count - 1]
)<<1)
+ ((oldptr[count - width - 1]
+ oldptr[count - width + 1]
+ oldptr[count + width - 1]
+ oldptr[count + width + 1]))
+ ( (
oldptr[count - (width*2)]
+ oldptr[count + (width*2)]
+ oldptr[count - 2]
+ oldptr[count + 2]
) >> 1 )
+ ( (
oldptr[count - (width*2) - 1]
+ oldptr[count - (width*2) + 1]
+ oldptr[count + (width*2) - 1]
+ oldptr[count + (width*2) + 1]
+ oldptr[count - 2 - width]
+ oldptr[count - 2 + width]
+ oldptr[count + 2 - width]
+ oldptr[count + 2 + width]
) >> 2 )
)
>> 3)
- (newptr[count]);
newptr[count] = newh - (newh >> density);
}
}
}
void MLImageFilterWater::DrawWaterNoLight(int page, MLImage* destination, const MLImage* source)
{
unsigned int brk = width * height;
int *ptr = hField1;
DWORD *dataS = (DWORD*)source->GetData();
DWORD *dataD = (DWORD*)destination->GetData();
for (unsigned int offset = 0; offset < brk; offset++)
{
int dx = ptr[offset] - ptr[offset + 1];
int dy = ptr[offset] - ptr[offset + width];
unsigned int index = offset + width * (dy>>3) + (dx>>3);
dataD[offset] = (index < brk ) ? dataS[offset + width*(dy>>3) + (dx>>3)] : dataS[offset];
}
}
void MLImageFilterWater::DrawWaterWithLight(MLImage* destination, const MLImage* source)
{
unsigned int brk = width * height;
int *ptr = hField1;
DWORD *dataS = (DWORD*)source->GetData();
DWORD *dataD = (DWORD*)destination->GetData();
for (unsigned int offset = 0; offset < brk; offset++)
{
int dx = ptr[offset] - ptr[offset + 1];
int dy = ptr[offset] - ptr[offset + width];
unsigned int index = offset + width * (dy>>3) + (dx>>3);
dataD[offset] = (index < brk ) ? GetShiftedColor(dataS[index], dx) : dataS[offset];
}
}
COLORREF MLImageFilterWater::GetShiftedColor(COLORREF color,int shift)
{
int R,G, B;
int r, g, b;
R = GetRValue(color)-shift;
G = GetGValue(color)-shift;
B = GetBValue(color)-shift;
r = (R < 0) ? 0 : (R > 255) ? 255 : R;
g = (G < 0) ? 0 : (G > 255) ? 255 : G;
b = (B < 0) ? 0 : (B > 255) ? 255 : B;
return RGB(r,g,b);
}
@@ -0,0 +1,47 @@
#ifndef NULLSOFT_ML_IMAGE_FILTERWATER_HEADER
#define NULLSOFT_ML_IMAGE_FILTERWATER_HEADER
#include <windows.h>
#include ".\image.h"
class MLImageFilterWater
{
public:
MLImageFilterWater(void);
~MLImageFilterWater(void);
public:
BOOL CreateFor(const MLImage *image);
void Render(MLImage* destination, const MLImage* source);
void CalculateWater(int page, int density);
void SmoothWater(int page);
void FlattenWater(void);
void SineBlob(int x, int y, int radius, int height, int page);
void WarpBlob(int x, int y, int radius, int height, int page);
void HeightBox (int x, int y, int radius, int height, int page);
void HeightBlob(int x, int y, int radius, int height, int page);
protected:
void ClearData(void);
void CalcWaterBigFilter(int page, int density);
void DrawWaterNoLight(int page,MLImage* destination, const MLImage* source);
void DrawWaterWithLight(MLImage* destination, const MLImage* source);
COLORREF GetShiftedColor(COLORREF color,int shift);
private:
HANDLE hHandle;
int height;
int width;
BOOL drawWithLight;
int lightModifier;
int hPage;
int density;
int* hField1;
int* hField2;
};
#endif //#define NULLSOFT_ML_IMAGE_FILTERWATER_HEADER
+209
View File
@@ -0,0 +1,209 @@
#include ".\image.h"
MLImage::MLImage(void)
{
loader = NULL;
loaderDelete = TRUE;
ResetData();
}
MLImage::MLImage(IMGLOADFUNC loader, BOOL deleteDone)
{
ResetData();
SetLoader(loader, deleteDone, FALSE);
}
MLImage::MLImage(int width, int height)
{
loader = NULL;
ResetData();
Init(width,height);
}
MLImage::~MLImage(void)
{
ResetData();
}
INT_PTR MLImage::SetLoader(IMGLOADFUNC loader, BOOL deleteDone, BOOL forceLoad)
{
this->loader = loader;
this->loaderDelete = deleteDone;
if (loader && forceLoad) Load();
return (loader != NULL) ? (INT_PTR) this : FALSE;
}
BOOL MLImage::Load(void)
{
ResetData();
if (!loader) return FALSE;
HBITMAP hbmpLoaded = loader((INT_PTR)this);
if(hbmpLoaded == NULL) return FALSE;
BITMAP bi;
if (GetObject(hbmpLoaded, sizeof(bi), &bi))
{
hbmp = ConvertTo32BppDIB(hbmpLoaded, bi.bmWidth, bi.bmHeight, &info, &data);
}
if (loaderDelete) DeleteObject(hbmpLoaded);
return (hbmp != NULL);
}
void MLImage::ResetData(void)
{
if (hbmp) DeleteObject(hbmp);
hbmp = NULL;
SecureZeroMemory(&info, sizeof(BITMAPINFO));
data = NULL;
}
BOOL MLImage::Draw(HDC hdcDest, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY)
{
if (!hbmp) return FALSE;
int realheight = abs(info.bmiHeader.biHeight);
int rsX = min(sourceX, info.bmiHeader.biWidth);
int rsY = min(sourceY, info.bmiHeader.biWidth);
int height = min(destHeight, realheight - rsY);
BOOL bResult = SetDIBitsToDevice( hdcDest, destX, destY,
min(destWidth, info.bmiHeader.biWidth - rsX), height,
rsX, realheight - height - rsY,
0, height,
data, &info, DIB_RGB_COLORS);
return bResult;
}
BOOL MLImage::Draw(HDC hdcDest, int destX, int destY)
{
return (!hbmp) ? FALSE : SetDIBitsToDevice( hdcDest, destX, destY,
info.bmiHeader.biWidth, abs(info.bmiHeader.biHeight),
0, 0,
0, abs(info.bmiHeader.biHeight),
data, &info, DIB_RGB_COLORS);
}
int MLImage::GetWidth(void) const
{
return (hbmp) ? info.bmiHeader.biWidth : 0;
}
int MLImage::GetHeight(void) const
{
return (hbmp) ? abs(info.bmiHeader.biHeight) : 0;
}
void* MLImage::GetData(void) const
{
return data;
}
HBITMAP MLImage::ConvertTo32BppDIB(HBITMAP bmpHandle, int bmpWidth, int bmpHeight, LPBITMAPINFO bmpInfo, LPVOID *bmpData)
{
HBITMAP hbmpNew = NULL;
HDC hdc = GetWindowDC(NULL);
HDC hdcTmp = CreateCompatibleDC(hdc);
HBITMAP hbmpTmp = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcTmp, hbmpTmp);
// render original bitmap to the temp dc
HDC hdcBmp = CreateCompatibleDC(hdc);
SelectObject(hdcBmp, bmpHandle);
BitBlt(hdcTmp, 0, 0, bmpWidth, bmpHeight, hdcBmp, 0,0, SRCCOPY);
SelectObject(hdcBmp, NULL);
DeleteDC(hdcBmp);
// Create a 32 bit bitmap
BITMAPINFO bih;
// create DIB Section
bih.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bih.bmiHeader.biWidth = bmpWidth;
bih.bmiHeader.biHeight = 0 - bmpHeight;
bih.bmiHeader.biPlanes = 1;
bih.bmiHeader.biBitCount = 32;
bih.bmiHeader.biCompression = BI_RGB;
bih.bmiHeader.biSizeImage = 0;
bih.bmiHeader.biXPelsPerMeter = 0;
bih.bmiHeader.biYPelsPerMeter = 0;
bih.bmiHeader.biClrUsed = 0;
bih.bmiHeader.biClrImportant = 0;
// Create a DC which will be used to get DIB, then create DIBsection
hbmpNew = CreateDIBSection(hdc, (const BITMAPINFO*) &bih, DIB_RGB_COLORS, bmpData, NULL, 0);
DWORD* line = (DWORD*)(*bmpData);
// Copy the bits into our 32 bit dib..
for(int i=0; i<bmpHeight; i++)
{
for(int j=0; j<bmpWidth; j++)
{
line[(i*bmpWidth) + j] = FIXCOLORREF(GetPixel(hdcTmp, j, i));
}
}
SelectObject(hdcTmp, hbmpOld);
ReleaseDC(NULL, hdc);
DeleteDC(hdcTmp);
memcpy(bmpInfo, &bih, sizeof(BITMAPINFO));
return hbmpNew;
}
MLImage* MLImage::Copy(MLImage* destination, const MLImage* original)
{
if (!destination) return NULL;
destination->ResetData();
destination->loader = original->loader;
destination->loaderDelete = original->loaderDelete;
destination->info = original->info;
HDC hdc = GetWindowDC(NULL);
destination->hbmp = CreateDIBSection(hdc, (const BITMAPINFO*) &destination->info, DIB_RGB_COLORS, &destination->data, NULL, 0);
CopyMemory(destination->data, original->data, 4*destination->GetHeight() * destination->GetWidth());
ReleaseDC(NULL, hdc);
return destination;
}
MLImage* MLImage::Init(int width, int height)
{
ResetData();
loader = NULL;
loaderDelete = TRUE;
// create DIB Section
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = width;
info.bmiHeader.biHeight = 0 - height;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = 0;
info.bmiHeader.biXPelsPerMeter = 0;
info.bmiHeader.biYPelsPerMeter = 0;
info.bmiHeader.biClrUsed = 0;
info.bmiHeader.biClrImportant = 0;
HDC hdc = GetWindowDC(NULL);
hbmp = CreateDIBSection(hdc, (const BITMAPINFO*) &info, DIB_RGB_COLORS, &data, NULL, 0);
ReleaseDC(NULL, hdc);
return this;
}
MLImage* MLImage::Init(int width, int height, COLORREF color)
{
Init(width, height);
int rColor = FIXCOLORREF(color);
DWORD *line = (DWORD*)(data);
DWORD *end = line + GetHeight() * GetWidth();
for(;line != end; line++) *line = rColor;
return this;
}
+61
View File
@@ -0,0 +1,61 @@
#ifndef NULLSOFT_ML_IMAGE_HEADER
#define NULLSOFT_ML_IMAGE_HEADER
#include <windows.h>
#define RGBA(r,g,b,a) ((COLORREF)(((BYTE)(r)|((WORD)(g)<<8))|(((DWORD)(BYTE)(b))<<16)|(((DWORD)(BYTE)(a))<<24)))
#define FIXCOLORREF(clr) RGBA(GetBValue(clr),GetGValue(clr), GetRValue(clr),((DWORD)(clr)) >> 24)
// loader function will be called every time MLImage need to
// reload picture. Input parameter - handle to the calling object
// Output - loaded bitmap
typedef HBITMAP (*IMGLOADFUNC)(INT_PTR handle);
class MLImage
{
public:
MLImage(void);
MLImage(IMGLOADFUNC loader, BOOL deleteDone);
MLImage(int width, int height);
~MLImage(void);
public:
// sets the loader function and returns handle to the class or NULL if error
// loader - pointer to the loader function
// deleteDone - if TRUE MLImage will delete HBITMAP object from loader every time it is done loading
// forceLoad - forcing to load bitamp immedialty by calling Load()
INT_PTR SetLoader(IMGLOADFUNC loader, BOOL deleteDone, BOOL forceLoad);
BOOL Load(void); // load image
MLImage* Init(int width, int height); // init image (allocates memory)
MLImage* Init(int width, int height, COLORREF color); // init image (allocates memory) and set
BOOL Draw(HDC hdcDest, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY); // draw image
BOOL Draw(HDC hdcDest, int destX, int destY); // draw image
public:
int GetWidth(void) const;
int GetHeight(void) const;
void* GetData(void) const;
private:
void ResetData(void);
public:
static MLImage* Copy(MLImage* destination, const MLImage* original);// copy all data from the original object (including image data) to the destination
private:
static HBITMAP ConvertTo32BppDIB(HBITMAP bmpHandle, int bmpWidth, int bmpHeight, LPBITMAPINFO bmpInfo, LPVOID *bmpData);
private:
IMGLOADFUNC loader; // pointer to the loader function
BOOL loaderDelete; // TRUE - delete HBITMAP from loader after load
HBITMAP hbmp; // my bitmap
BITMAPINFO info;
void *data;
};
#endif // NULLSOFT_ML_IMAGE_HEADER
@@ -0,0 +1,91 @@
#include ".\imagefilters.h"
void MLImageFilter_GrayScale(MLImage *image)
{
DWORD *line = (DWORD*)(image->GetData());
DWORD *end = line + image->GetHeight() * image->GetWidth();
for(;line != end; line++)
{
BYTE y = (BYTE)(0.3f * GetBValue(*line) + 0.59f *GetGValue(*line) + 0.11f *GetRValue(*line));
*line = RGB(y,y,y);
}
}
void MLImageFilter_Invert(MLImage *image)
{
DWORD *line = (DWORD*)(image->GetData());
DWORD *end = line + image->GetHeight() * image->GetWidth();
for(;line != end; line++) *line = ((~*line) & 0x00FFFFFF) | (*line & 0xFF000000);
}
void MLImageFilter_SetToColor(MLImage *image, COLORREF color)
{
COLORREF rColor = FIXCOLORREF(color);
DWORD *line = (DWORD*)(image->GetData());
DWORD *end = line + image->GetHeight() * image->GetWidth();
for(;line != end; line++) *line = rColor;
}
void MLImageFilter_Fader1(MLImage *dest, const MLImage* source, COLORREF color)
{
int len = dest->GetHeight() * dest->GetWidth();
BYTE r = GetRValue(color), g = GetGValue(color), b = GetBValue(color);
DWORD *dataS = (DWORD*)(source->GetData());
DWORD *dataD = (DWORD*)(dest->GetData());
DWORD *end = dataD + len;
for(;dataD != end; dataD++, dataS++)
{
*dataD = RGB( max(b, GetRValue(*dataS)), max(g, GetGValue(*dataS)), max(r, GetBValue(*dataS))) ;
}
}
void MLImageFilter_Fader2(MLImage *dest, const MLImage* source, COLORREF color)
{
int len = dest->GetHeight() * dest->GetWidth();
BYTE r = GetRValue(color), g = GetGValue(color), b = GetBValue(color);
DWORD *dataS = (DWORD*)(source->GetData());
DWORD *dataD = (DWORD*)(dest->GetData());
DWORD *end = dataD + len;
for(;dataD != end; dataD++, dataS++)
{
*dataD = RGB( min(b, GetRValue(*dataS)), min(g, GetGValue(*dataS)), min(r, GetBValue(*dataS))) ;
}
}
void MLImageFilter_Fader3(MLImage *dest, const MLImage* source, int koeff)
{
int len = dest->GetHeight() * dest->GetWidth();
DWORD *dataS = (DWORD*)(source->GetData());
DWORD *dataD = (DWORD*)(dest->GetData());
DWORD *end = dataD + len;
for(;dataD != end; dataD++, dataS++)
{
*dataD = RGB(min(255,GetRValue(*dataS) + koeff), min(255,GetGValue(*dataS) + koeff), min(255, GetBValue(*dataS) + koeff));
}
}
void MLImageFilter_Blend1(MLImage *dest, MLImage *src1, int destX, int destY, int width, int height, const MLImage* src2, int srcX, int srcY, COLORREF color)
{
int widthS1 = src1->GetWidth();
int widthS2 = src2->GetWidth();
DWORD *dataD = (DWORD*)(dest->GetData()) + destY * widthS1 + destX;
DWORD *dataS1 = (DWORD*)(src1->GetData()) + destY * widthS1 + destX;
DWORD *dataS2 = (DWORD*)(src2->GetData()) + srcY * widthS2 + srcX;
DWORD *curS1;
for (int y = 0; y < height; y++)
{
DWORD *curD = dataD + y * widthS1;
curS1 = dataS1 + y * widthS1;
DWORD *curS2 = dataS2 + y * widthS2;
for (DWORD *end = curS1 + width; end != curS1; curD++, curS1++, curS2++)
{
*curD = (*curS1 == color) ? *curS2 : *curS1;
}
}
}
@@ -0,0 +1,17 @@
#ifndef NULLSOFT_ML_IMAGE_FILTER_HEADER
#define NULLSOFT_ML_IMAGE_FILTER_HEADER
#include <windows.h>
#include ".\image.h"
#include ".\filterwater.h"
void MLImageFilter_GrayScale(MLImage *image);
void MLImageFilter_Invert(MLImage *image);
void MLImageFilter_SetToColor(MLImage *image, COLORREF color);
void MLImageFilter_Fader1(MLImage *dest, const MLImage* source, COLORREF color);
void MLImageFilter_Fader2(MLImage *dest, const MLImage* source, COLORREF color);
void MLImageFilter_Fader3(MLImage *dest, const MLImage* source, int koeff);
void MLImageFilter_Blend1(MLImage *dest, MLImage *src1, int destX, int destY, int width, int height, const MLImage* src2, int srcX, int srcY, COLORREF color);
#endif //NULLSOFT_ML_IMAGE_FILTER_HEADER
+556
View File
@@ -0,0 +1,556 @@
#include "../id3v2/id3_tag.h"
#include "id3.h"
#include "config.h"
#include "../nu/ns_wc.h"
#include <strsafe.h>
#define _isdigit(x) (( x ) >= '0' && ( x ) <= '9')
/* id3 helper functions */
void SetFrameEncoding(ID3_Frame *frame, int encoding)
{
switch (encoding)
{
case ENCODING_AUTO:
if (config_write_mode == WRITE_UTF16)
frame->Field(ID3FN_TEXTENC).Set(ID3TE_UNICODE);
else
frame->Field(ID3FN_TEXTENC).Set(ID3TE_ASCII);
break;
case ENCODING_FORCE_ASCII:
frame->Field(ID3FN_TEXTENC).Set(ID3TE_ASCII);
break;
case ENCODING_FORCE_UNICODE:
frame->Field(ID3FN_TEXTENC).Set(ID3TE_UNICODE);
break;
}
}
char *ID3_GetString(ID3_Frame *frame, ID3_FieldID fldName, size_t nIndex)
{
char *text = NULL;
if (NULL != frame)
{
size_t nText = frame->Field(fldName).Size();
text = (char *)calloc(nText + 1, sizeof(char));
frame->Field(fldName).GetLocal(text, nText + 1, nIndex);
}
return text;
}
wchar_t *ID3_GetUnicodeString(ID3_Frame *frame, ID3_FieldID fldName, size_t nIndex)
{
wchar_t *text = NULL;
if (NULL != frame)
{
size_t nText = frame->Field(fldName).Size();
text = (wchar_t *)calloc(sizeof(wchar_t) * (nText + 1), sizeof(wchar_t));
frame->Field(fldName).GetUnicode(text, nText + 1, nIndex);
}
return text;
}
wchar_t *ID3_FillUnicodeString(ID3_Frame *frame, ID3_FieldID fldName, wchar_t *dest, size_t destlen, size_t nIndex)
{
memset(dest, 0, destlen * sizeof(wchar_t));
if (NULL != frame)
{
frame->Field(fldName).GetUnicode(dest, destlen, nIndex);
return dest;
}
else
return NULL;
}
wchar_t *ID3_GetTitle(ID3_Tag *tag)
{
wchar_t*sTitle = NULL;
if (NULL == tag)
{
return sTitle;
}
ID3_Frame *frame = tag->Find(ID3FID_TITLE);
if (frame != NULL)
{
sTitle = ID3_GetUnicodeString(frame, ID3FN_TEXT);
}
return sTitle;
}
wchar_t *ID3_GetArtist(ID3_Tag *tag)
{
if (!tag) return 0;
wchar_t *sArtist = NULL;
ID3_Frame *frame = NULL;
if ((frame = tag->Find(ID3FID_LEADARTIST)) || (frame = tag->Find(ID3FID_BAND)))
{
sArtist = ID3_GetUnicodeString(frame, ID3FN_TEXT);
}
return sArtist;
}
wchar_t *ID3_GetAlbum(ID3_Tag *tag)
{
wchar_t *sAlbum = NULL;
if (NULL == tag)
{
return sAlbum;
}
ID3_Frame *frame = tag->Find(ID3FID_ALBUM);
if (frame != NULL)
{
sAlbum = ID3_GetUnicodeString(frame, ID3FN_TEXT);
}
return sAlbum;
}
wchar_t *ID3_GetYear(ID3_Tag *tag)
{
wchar_t *sYear = NULL;
if (NULL == tag)
{
return sYear;
}
ID3_Frame *frame = tag->Find(ID3FID_RECORDINGTIME);
if (frame != NULL)
sYear = ID3_GetUnicodeString(frame, ID3FN_TEXT);
if (!sYear || !*sYear)
{
frame = tag->Find(ID3FID_YEAR);
if (frame != NULL)
sYear = ID3_GetUnicodeString(frame, ID3FN_TEXT);
}
return sYear;
}
void ID3_AddSetComment(ID3_Tag *tag, const wchar_t *comment)
{
ID3_Frame *frame = tag->Find(ID3FID_COMMENT, ID3FN_DESCRIPTION, L"");
if (frame)
{
if (!comment || !comment[0])
tag->RemoveFrame(frame);
else
{
SetFrameEncoding(frame);
frame->Field(ID3FN_TEXT).SetUnicode(comment);
unsigned char null3[3] = {0, 0, 0};
frame->Field(ID3FN_LANGUAGE).Get(null3, 3);
if (!null3[0]) frame->Field(ID3FN_LANGUAGE).SetLatin("eng");
}
}
else if (comment && comment[0])
{
frame = new ID3_Frame(ID3FID_COMMENT);
SetFrameEncoding(frame);
frame->Field(ID3FN_LANGUAGE).SetLatin("eng");
//frame->Field(ID3FN_LANGUAGE).Set(null3, 3);
frame->Field(ID3FN_DESCRIPTION).SetUnicode(L"");
frame->Field(ID3FN_TEXT).SetUnicode(comment);
tag->AddFrame(frame, TRUE);
}
}
void ID3_AddSetRating(ID3_Tag *tag, const wchar_t *rating)
{
luint rating_integer = 0;
if (rating)
rating_integer = _wtoi(rating);
bool custom_frame = false, own_frame = false;
ID3_Frame* frame = NULL;
if (config_rating_email[0])
{
frame = tag->Find(ID3FID_POPULARIMETER, ID3FN_EMAIL, config_rating_email);
if (!frame) custom_frame = true;
}
if (!frame)
{
frame = tag->Find(ID3FID_POPULARIMETER, ID3FN_EMAIL, "rating@winamp.com\0");
if (frame) own_frame = true;
}
if (!frame)
{
frame = tag->Find(ID3FID_POPULARIMETER);
if (frame) own_frame = true;
}
// try to use a custom field if our own was present and the custom wasn't
if (custom_frame && own_frame)
{
frame->Clear();
frame = NULL;
}
if (!frame)
{
frame = new ID3_Frame(ID3FID_POPULARIMETER);
if (!config_rating_email[0])
frame->Field(ID3FN_EMAIL).Set((uchar *)"rating@winamp.com\0", 18);
else
{
frame->Field(ID3FN_EMAIL).Set((uchar *)config_rating_email, strlen(config_rating_email)+1);
}
tag->AddFrame(frame, TRUE);
}
if (frame)
{
switch(rating_integer)
{
case 2:
rating_integer=64;
break;
case 3:
rating_integer=128;
break;
case 4:
rating_integer=196;
break;
case 5:
rating_integer = 255;
break;
}
if (!rating_integer)
tag->RemoveFrame(frame);
else
frame->Field(ID3FN_RATING).Set(rating_integer);
}
}
wchar_t *ID3_GetComment(ID3_Tag *tag, wchar_t *dest, size_t destlen)
{
wchar_t *comment = NULL;
if (NULL == tag)
{
return comment;
}
ID3_Frame* frame = tag->Find(ID3FID_COMMENT, ID3FN_DESCRIPTION, L"");
if (frame)
{
comment = ID3_FillUnicodeString(frame, ID3FN_TEXT, dest, destlen);
}
return comment;
}
wchar_t *ID3_GetRating(ID3_Tag *tag, wchar_t *dest, size_t destlen)
{
if (NULL == tag)
{
return NULL;
}
ID3_Frame* frame = NULL;
if (config_rating_email[0])
frame = tag->Find(ID3FID_POPULARIMETER, ID3FN_EMAIL, config_rating_email);
if (!frame)
frame = tag->Find(ID3FID_POPULARIMETER, ID3FN_EMAIL, "rating@winamp.com\0");
if (!frame)
frame = tag->Find(ID3FID_POPULARIMETER);
if (frame)
{
int rating = (int)frame->Field(ID3FN_RATING).Get();
if (rating >= 224 && rating <= 255)
rating = 5;
else if (rating >= 160 && rating <= 223)
rating = 4;
else if (rating >= 96 && rating <= 159)
rating = 3;
else if (rating >= 32 && rating <= 95)
rating = 2;
else if (rating >= 1 && rating <= 31)
rating = 1;
else
rating = 0;
StringCchPrintfW(dest, destlen, L"%u", rating);
return dest;
}
return 0;
}
wchar_t *ID3_GetComment(ID3_Tag *tag, const wchar_t *desc, wchar_t *dest, size_t destlen)
{
wchar_t *comment = NULL;
if (NULL == tag)
{
return comment;
}
ID3_Frame* frame = tag->Find(ID3FID_COMMENT, ID3FN_DESCRIPTION, desc);
if (frame)
{
comment = ID3_FillUnicodeString(frame, ID3FN_TEXT, dest, destlen);
}
return comment;
}
wchar_t *ID3_GetMusicbrainzRecordingID(ID3_Tag *tag, wchar_t *dest, size_t destlen)
{
if (NULL == tag)
{
return 0;
}
ID3_Frame* frame = tag->Find(ID3FID_UNIQUEFILEID, ID3FN_OWNER, L"http://musicbrainz.org");
if (frame)
{
uchar data[64] = {0};
luint dataSize = frame->Field(ID3FN_DATA).Size();
frame->Field(ID3FN_DATA).Get(data, 64);
int converted = MultiByteToWideCharSZ(CP_ACP, 0, (const char *)data, (int)dataSize, dest, (int)destlen);
dest[converted]=0;
return dest;
}
return 0;
}
wchar_t *ID3_GetGracenoteTagID(ID3_Tag *tag)
{
if (NULL == tag)
{
return 0;
}
ID3_Frame* frame = tag->Find(ID3FID_UNIQUEFILEID, ID3FN_OWNER, L"http://www.cddb.com/id3/taginfo1.html");
if (frame)
{
uchar data[64] = {0};
luint dataSize = frame->Field(ID3FN_DATA).Size();
frame->Field(ID3FN_DATA).Get(data, 64);
int converted = MultiByteToWideChar(CP_ACP, 0, (const char *)data, (int)dataSize, 0, 0);
wchar_t *dest = (wchar_t *)calloc((converted+1), sizeof(wchar_t));
converted = MultiByteToWideChar(CP_ACP, 0, (const char *)data, (int)dataSize, dest, converted);
dest[converted]=0;
return dest;
}
return 0;
}
wchar_t *ID3_GetGracenoteTagID(ID3_Tag *tag, wchar_t *dest, size_t destlen)
{
if (NULL == tag)
{
return 0;
}
ID3_Frame* frame = tag->Find(ID3FID_UNIQUEFILEID, ID3FN_OWNER, L"http://www.cddb.com/id3/taginfo1.html");
if (frame)
{
uchar data[64] = {0};
luint dataSize = frame->Field(ID3FN_DATA).Size();
frame->Field(ID3FN_DATA).Get(data, 64);
int converted = MultiByteToWideCharSZ(CP_ACP, 0, (const char *)data, (int)dataSize, dest, (int)destlen);
dest[converted]=0;
return dest;
}
return 0;
}
void ID3_AddSetGracenoteTagID(ID3_Tag *tag, const wchar_t *tagID)
{
ID3_Frame *frame = tag->Find(ID3FID_UNIQUEFILEID, ID3FN_OWNER, L"http://www.cddb.com/id3/taginfo1.html");
if (frame)
{
if (!tagID || !tagID[0])
tag->RemoveFrame(frame);
else
{
size_t origLen = wcslen(tagID); // so we can not write the null terminator
uchar data[64] = {0};
luint dataSize = WideCharToMultiByte(CP_ACP, 0, tagID, (int)origLen, (char *)data, 64, 0, 0);
frame->Field(ID3FN_DATA).Set(data, dataSize);
}
}
else if (tagID && tagID[0])
{
frame = new ID3_Frame(ID3FID_UNIQUEFILEID);
SetFrameEncoding(frame, ENCODING_FORCE_ASCII);
frame->Field(ID3FN_OWNER).SetLatin("http://www.cddb.com/id3/taginfo1.html");
size_t origLen = wcslen(tagID); // so we can not write the null terminator
uchar data[64] = {0};
luint dataSize = WideCharToMultiByte(CP_ACP, 0, tagID, (int)origLen, (char *)data, 64, 0, 0);
frame->Field(ID3FN_DATA).Set(data, dataSize);
tag->AddFrame(frame, TRUE);
}
}
#if 0 // benski> CUT
char *ID3_GetTUID(ID3_Tag *tag)
{
char *tuid = NULL;
if (NULL == tag)
{
return tuid;
}
ID3_Frame* frame = NULL;
frame = tag->Find(ID3FID_UNIQUEFILEID);
if (frame)
{
char *tmp = ID3_GetString(frame, ID3FN_DATA);
if (tmp)
{
// verify first four characters are '3CD3'
if (!strncmp(tmp, "3CD3", 4))
{
char m, n;
char *p = tmp + 4;
n = *p++;
m = 'P' - n;
p += m;
n = *p++;
m = 'Z' - n; // length of TUID;
tuid = _strdup(p);
tuid[m] = 0; // null terminate
}
free(tmp);
}
}
return tuid;
}
#endif
char *ID3_GetGenre(ID3_Tag *tag)
{
char *sGenre = NULL;
if (NULL == tag)
{
return sGenre;
}
ID3_Frame *frame = tag->Find(ID3FID_CONTENTTYPE);
if (frame != NULL)
{
sGenre = ID3_GetString(frame, ID3FN_TEXT);
}
return sGenre;
}
void ID3_AddUserText(ID3_Tag *tag, wchar_t *desc, const wchar_t *value, int encoding)
{
ID3_Frame *frame = tag->Find(ID3FID_USERTEXT, ID3FN_DESCRIPTION, desc);
if (frame)
{
if (!value || !value[0])
tag->RemoveFrame(frame);
else
{
SetFrameEncoding(frame, encoding);
frame->Field(ID3FN_TEXT).SetUnicode(value);
}
}
else if (value && value[0])
{
frame = new ID3_Frame(ID3FID_USERTEXT);
SetFrameEncoding(frame, encoding);
frame->Field(ID3FN_DESCRIPTION).SetUnicode(desc);
frame->Field(ID3FN_TEXT).SetUnicode(value);
tag->AddFrame(frame, TRUE);
}
}
wchar_t *ID3_GetUserText(ID3_Tag *tag, wchar_t *desc)
{
if (tag == NULL)
return NULL;
ID3_Frame *frame = tag->Find(ID3FID_USERTEXT, ID3FN_DESCRIPTION, desc);
if (frame)
return ID3_GetUnicodeString(frame, ID3FN_TEXT);
else
return 0;
}
wchar_t *ID3_GetUserText(ID3_Tag *tag, wchar_t *desc, wchar_t *dest, size_t destlen)
{
if (tag == NULL)
return NULL;
ID3_Frame *frame = tag->Find(ID3FID_USERTEXT, ID3FN_DESCRIPTION, desc);
if (frame)
return ID3_FillUnicodeString(frame, ID3FN_TEXT, dest, destlen);
else
return 0;
}
wchar_t *ID3_GetTagText(ID3_Tag *tag, ID3_FrameID f)
{
wchar_t *sComposer = NULL;
if (NULL == tag)
{
return sComposer;
}
ID3_Frame *frame = tag->Find(f);
if (frame != NULL)
{
sComposer = ID3_GetUnicodeString(frame, ID3FN_TEXT);
}
return sComposer;
}
wchar_t *ID3_GetTagText(ID3_Tag *tag, ID3_FrameID f, wchar_t *dest, size_t destlen)
{
wchar_t *sComposer = NULL;
if (NULL == tag)
{
return sComposer;
}
ID3_Frame *frame = tag->Find(f);
if (frame != NULL)
{
sComposer = ID3_FillUnicodeString(frame, ID3FN_TEXT, dest, destlen);
}
return sComposer;
}
wchar_t *ID3_GetTagUrl(ID3_Tag *tag, ID3_FrameID f, wchar_t *dest, size_t destlen)
{
wchar_t *sComposer = NULL;
if (NULL == tag)
{
return sComposer;
}
ID3_Frame *frame = tag->Find(f);
if (frame != NULL)
{
sComposer = ID3_FillUnicodeString(frame, ID3FN_URL, dest, destlen);
}
return sComposer;
}
#if 0
char *ID3_GetGenreDisplayable(ID3_Tag *tag)
{
char *sGenre = ID3_GetGenre(tag);
if (!sGenre) return NULL;
while (sGenre && *sGenre == ' ') sGenre++;
if (sGenre[0] == '(' || _isdigit(sGenre[0]))
{
int isparam = !_isdigit(sGenre[0]);
char *pCur = &sGenre[isparam];
int cnt = 0;
while (_isdigit(*pCur))
{
cnt++;
pCur++;
}
while (pCur && *pCur == ' ') pCur++;
if (cnt > 0 && (isparam && *pCur == ')') || (!isparam && !*pCur))
{
// if the genre number is greater than 255, its invalid.
size_t ulGenre = atoi(&sGenre[isparam]);
if (ulGenre >= 0 && ulGenre < numberOfGenres)
{
char *tmp = (char*)malloc(strlen(genres[ulGenre]) + 1);
if (tmp)
{
memcpy(tmp, genres[ulGenre], strlen(genres[ulGenre]) + 1);
free(sGenre);
sGenre = tmp;
}
}
}
}
return sGenre;
}
#endif
+43
View File
@@ -0,0 +1,43 @@
#ifndef NULLSOFT_IN_MP3_IN_H
#define NULLSOFT_IN_MP3_IN_H
extern char *genres[];
extern size_t numberOfGenres;
enum
{
ENCODING_AUTO=0,
ENCODING_FORCE_ASCII = 1,
ENCODING_FORCE_UNICODE = 2,
};
char *ID3_GetString(ID3_Frame *frame, ID3_FieldID fldName, size_t nIndex=1);
wchar_t *ID3_GetUnicodeString(ID3_Frame *frame, ID3_FieldID fldName, size_t nIndex=1);
wchar_t *ID3_FillUnicodeString(ID3_Frame *frame, ID3_FieldID fldName, wchar_t *dest, size_t destlen, size_t nIndex=1);
wchar_t *ID3_GetTitle(ID3_Tag *tag);
wchar_t *ID3_GetArtist(ID3_Tag *tag);
//char *ID3_GetAlbumLocal(ID3_Tag *tag);
wchar_t *ID3_GetAlbum(ID3_Tag *tag);
wchar_t *ID3_GetYear(ID3_Tag *tag);
wchar_t *ID3_GetComment(ID3_Tag *tag, wchar_t *dest, size_t destlen);
wchar_t *ID3_GetComment(ID3_Tag *tag, const wchar_t *desc, wchar_t *dest, size_t destlen);
char *ID3_GetTUID(ID3_Tag *tag);
char *ID3_GetGenre(ID3_Tag *tag);
wchar_t *ID3_GetTagText(ID3_Tag *tag, ID3_FrameID f);
wchar_t *ID3_GetTagText(ID3_Tag *tag, ID3_FrameID f, wchar_t *dest, size_t destlen);
wchar_t *ID3_GetTagUrl(ID3_Tag *tag, ID3_FrameID f, wchar_t *dest, size_t destlen);
char *ID3_GetGenreDisplayable(ID3_Tag *tag);
wchar_t *ID3_GetUserText(ID3_Tag *tag, wchar_t *desc);
wchar_t *ID3_GetUserText(ID3_Tag *tag, wchar_t *desc, wchar_t *dest, size_t destlen);
void ID3_AddUserText(ID3_Tag *tag, wchar_t *desc, const wchar_t *value, int encoding=ENCODING_AUTO);
void ID3_AddSetComment(ID3_Tag *tag, const wchar_t *comment);
void ID3_AddSetRating(ID3_Tag *tag, const wchar_t *rating);
wchar_t *ID3_GetRating(ID3_Tag *tag, wchar_t *dest, size_t destlen);
wchar_t *ID3_GetMusicbrainzRecordingID(ID3_Tag *tag, wchar_t *dest, size_t destlen);
wchar_t *ID3_GetGracenoteTagID(ID3_Tag *tag);
wchar_t *ID3_GetGracenoteTagID(ID3_Tag *tag, wchar_t *dest, size_t destlen);
void ID3_AddSetGracenoteTagID(ID3_Tag *tag, const wchar_t *tagID);
void SetFrameEncoding(ID3_Frame *frame, int encoding = ENCODING_AUTO);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,45 @@
#pragma once
#include <bfc/dispatch.h>
class ifc_mpeg_stream_reader : public Dispatchable
{
protected:
ifc_mpeg_stream_reader() {}
~ifc_mpeg_stream_reader() {}
public:
int MPEGStream_Peek( void *buffer, size_t to_read, size_t *bytes_read );
int MPEGStream_Read( void *buffer, size_t to_read, size_t *bytes_read );
int MPEGStream_EOF();
float MPEGStream_Gain();
DISPATCH_CODES
{
MPEGSTREAM_PEEK = 0,
MPEGSTREAM_READ = 1,
MPEGSTREAM_EOF = 2,
MPEGSTREAM_GAIN = 3,
};
};
inline int ifc_mpeg_stream_reader::MPEGStream_Peek( void *buffer, size_t to_read, size_t *bytes_read )
{
return _call( MPEGSTREAM_PEEK, (int)1, buffer, to_read, bytes_read );
}
inline int ifc_mpeg_stream_reader::MPEGStream_Read( void *buffer, size_t to_read, size_t *bytes_read )
{
return _call( MPEGSTREAM_READ, (int)1, buffer, to_read, bytes_read );
}
inline int ifc_mpeg_stream_reader::MPEGStream_EOF()
{
return _call( MPEGSTREAM_EOF, (int)true );
}
inline float ifc_mpeg_stream_reader::MPEGStream_Gain()
{
return _call( MPEGSTREAM_GAIN, (float)1.0f );
}
+503
View File
@@ -0,0 +1,503 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PREFS, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 220
TOPMARGIN, 6
BOTTOMMARGIN, 121
END
IDD_OUTPUT, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 220
TOPMARGIN, 6
BOTTOMMARGIN, 156
END
IDD_HTTP, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 220
TOPMARGIN, 6
BOTTOMMARGIN, 148
END
IDD_TAGOPTS, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 220
TOPMARGIN, 6
BOTTOMMARGIN, 163
END
IDD_HTTPAUTH, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 153
TOPMARGIN, 7
BOTTOMMARGIN, 71
END
IDD_ADVANCED_TAGGING, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 220
TOPMARGIN, 6
BOTTOMMARGIN, 116
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#include ""version.rc2""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PREFS DIALOGEX 0, 0, 226, 127
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "General"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "File Association",IDC_STATIC,6,6,214,61
LTEXT "Extension list (semicolon delimited):",IDC_STATIC,12,18,140,8
EDITTEXT IDC_EDIT1,12,31,201,12,ES_AUTOHSCROLL
PUSHBUTTON "Set to default",IDC_BUTTON1,12,49,50,13
LTEXT "Default: MP3;MP2;MP1;AAC;VLB",IDC_STATIC,68,51,144,8
GROUPBOX "Full File Buffering",IDC_STATIC,6,71,214,32
LTEXT "Buffer the entire file from disk if the file is smaller than:",IDC_STATIC,13,81,115,16
EDITTEXT IDC_BUFMAX,141,83,24,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "kilobytes",IDC_STATIC,169,85,28,8
END
IDD_OUTPUT DIALOGEX 0, 0, 226, 163
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Decoder"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "Quality",IDC_STATIC,6,2,213,50
CONTROL "&Full",IDC_FULLRATE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,12,30,10
CONTROL "&Half",IDC_HALFRATE,"Button",BS_AUTORADIOBUTTON,12,24,30,10
CONTROL "&Quarter",IDC_QRATE,"Button",BS_AUTORADIOBUTTON,12,36,40,10
LTEXT "Selecting 'Half' or 'Quarter' quality will downsample the output, resulting in less processor usage.",IDC_STATIC,80,12,125,34
GROUPBOX "Misc Options",IDC_STATIC,6,55,213,40
CONTROL "CRC checking",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,67,105,10
CONTROL "Show average bitrate on VBR files",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,12,80,180,10
GROUPBOX "Equalizer",IDC_STATIC,6,98,213,61
CONTROL "Logarithmic EQ (default)",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,12,110,128,10
CONTROL "Linear EQ",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,12,120,72,10
CONTROL "Fast Layer 3 EQ",IDC_FASTL3EQ,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,132,98,10
CONTROL "Fast Layer 1/2 EQ",IDC_FASTL12EQ,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,144,106,10
END
IDD_HTTP DIALOGEX 0, 0, 226, 154
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Streaming"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "Streaming Data Buffer",IDC_STATIC,6,6,86,64
EDITTEXT IDC_BUFFERS_NUMBUFS,12,18,27,12
LTEXT "KB",IDC_STATIC,42,20,10,8
LTEXT "Increase this value to give better skip protection on slower connections.",IDC_STATIC,12,33,73,33
GROUPBOX "Streaming Prebuffer",IDC_STATIC,96,6,124,100
CONTROL "Slider1",IDC_PREBUFSLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,102,18,111,10
CTEXT "0% 50% 100%",IDC_STATIC,103,31,110,8
CTEXT "(how much to prebuffer at the start of a stream)",IDC_STATIC,105,42,105,16
CONTROL "Slider1",IDC_PREBUFSLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,102,61,111,10
CTEXT "0% 50% 100%",IDC_STATIC,103,74,110,8
CTEXT "(how much to prebuffer after a buffer underrun)",IDC_STATIC,105,85,105,16
GROUPBOX "Streaming Extensions",IDC_STATIC,6,72,86,76
CONTROL "Enable SHOUTcast title support",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,12,83,74,18
CONTROL "Include stream name in title",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,12,105,74,18
CONTROL "Enable SHOUTcast v2 artwork support",IDC_SC_ARTWORK,
"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,12,126,74,18
GROUPBOX "Saving",IDC_STATIC,96,110,124,38
CONTROL "Save files to:",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,120,57,10
PUSHBUTTON "",IDC_BUTTON2,102,132,112,11
END
IDD_TAGOPTS DIALOGEX 0, 0, 226, 168
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "ID3 Tags"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "ID3 Tag Reading",IDC_STATIC,6,6,214,122
CONTROL "Read ID3v1 tags",IDC_READ_ID3V1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,70,10
CONTROL "Read ID3v2 tags",IDC_READ_ID3V2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,31,70,10
LTEXT "Read ASCII tags as:",IDC_STATIC,98,16,65,8
COMBOBOX IDC_COMBO1,109,28,80,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "ID3 Tag Writing",IDC_STATIC,6,47,214,81
CONTROL "Modify ID3v1 tags",IDC_WRITE_ID3V1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,60,73,10
CONTROL "Modify ID3v2 tags",IDC_WRITE_ID3V2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,72,73,10
LTEXT "Write tags as:",IDC_STATIC,98,56,45,8
COMBOBOX IDC_COMBO2,109,67,80,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "ID3 Tag Creation",IDC_STATIC,6,86,214,42
CONTROL "Create new ID3v1 tags when adding metadata",IDC_CREATE_ID3V1,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,100,163,10
LTEXT "",IDC_STATIC,17,107,8,8
CONTROL "Create new ID3v2 tags when adding metadata",IDC_CREATE_ID3V2,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,112,163,10
GROUPBOX "ID3v2 Tag Rating Field Email Address",IDC_STATIC,6,132,214,31
EDITTEXT IDC_RATING_EMAIL,13,144,162,12,ES_AUTOHSCROLL
PUSHBUTTON "Reset",IDC_RATING_EMAIL_RESET,179,143,36,14
END
IDD_HTTPAUTH DIALOGEX 0, 0, 160, 76
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "HTTP Login Required"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "Realm: ",IDC_STATIC,7,7,25,8
LTEXT "",IDC_REALM,40,7,113,8
LTEXT "Enter your login and password in the form of:\n\tlogin:password",IDC_STATIC,7,18,146,17
EDITTEXT IDC_EDIT1,7,39,146,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,7,58,50,13
PUSHBUTTON "Cancel",IDCANCEL,61,58,50,13
END
IDD_INFO_ID3V1 DIALOGEX 0, 0, 341, 164
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "ID3v1",IDC_STATIC,0,0,175,133
CONTROL "&Include ID3v1 tag in file",IDC_ID3V1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,9,100,10
RTEXT "Track #",IDC_STATIC,7,24,36,8
EDITTEXT IDC_ID3V11_TRACK,46,22,19,12,ES_AUTOHSCROLL | ES_NUMBER
RTEXT "Title",IDC_STATIC,7,39,36,8
EDITTEXT IDC_ID3_TITLE,46,37,124,12,ES_AUTOHSCROLL
RTEXT "Artist",IDC_STATIC,7,54,36,8
EDITTEXT IDC_ID3_ARTIST,46,52,124,12,ES_AUTOHSCROLL
RTEXT "Album",IDC_STATIC,7,69,36,8
EDITTEXT IDC_ID3_ALBUM,46,67,124,12,ES_AUTOHSCROLL
RTEXT "Year",IDC_STATIC,7,83,36,8
EDITTEXT IDC_ID3_YEAR,46,81,31,12,ES_NUMBER
RTEXT "Genre",IDC_STATIC,81,83,22,8
COMBOBOX IDC_ID3_GENRE,106,81,64,159,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Comment",IDC_STATIC,7,99,36,8
EDITTEXT IDC_ID3_COMMENT,46,97,123,12,ES_AUTOHSCROLL
PUSHBUTTON "Copy &to ID3v2",IDC_ID3V1_TO_V2,107,113,62,14
END
IDD_INFO_ID3V2 DIALOGEX 0, 0, 341, 164
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "ID3v2",IDC_STATIC,0,0,341,164
CONTROL "&Include ID3v2 tag in file",IDC_ID3V2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,9,108,10
RTEXT "Track #",IDC_STATIC,7,24,36,8
EDITTEXT IDC_ID3V2_TRACK,46,22,36,12,ES_AUTOHSCROLL
RTEXT "Disc #",IDC_STATIC,90,24,36,8
EDITTEXT IDC_ID3V2_DISC,128,22,42,12,ES_AUTOHSCROLL
RTEXT "Title",IDC_STATIC,7,39,36,8
EDITTEXT IDC_ID3V2_TITLE,46,37,124,12,ES_AUTOHSCROLL
RTEXT "Artist",IDC_STATIC,7,54,36,8
EDITTEXT IDC_ID3V2_ARTIST,46,52,124,12,ES_AUTOHSCROLL
RTEXT "Album",IDC_STATIC,7,69,36,8
EDITTEXT IDC_ID3V2_ALBUM,46,67,124,12,ES_AUTOHSCROLL
RTEXT "Year",IDC_STATIC,7,83,36,8
EDITTEXT IDC_ID3V2_YEAR,46,81,31,12,ES_AUTOHSCROLL | ES_NUMBER
RTEXT "Genre",IDC_STATIC,81,83,22,8
COMBOBOX IDC_ID3V2_GENRE,106,81,64,159,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Comment",IDC_STATIC,7,99,36,8
EDITTEXT IDC_ID3V2_COMMENT,46,97,124,29,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
RTEXT "Album Artist",IDC_STATIC,3,131,40,8
EDITTEXT IDC_ID3V2_ALBUM_ARTIST,46,129,124,12,ES_AUTOHSCROLL
RTEXT "Composer",IDC_STATIC,7,146,36,8
EDITTEXT IDC_ID3V2_COMPOSER,46,144,124,12,ES_AUTOHSCROLL
RTEXT "Publisher",IDC_STATIC,172,24,37,8
EDITTEXT IDC_ID3V2_PUBLISHER,212,22,124,12,ES_AUTOHSCROLL
RTEXT "Orig. Artist",IDC_STATIC,173,39,36,8
EDITTEXT IDC_ID3V2_MARTIST,212,37,124,12,ES_AUTOHSCROLL
RTEXT "Copyright",IDC_STATIC,173,54,36,8
EDITTEXT IDC_ID3V2_RECORD,212,52,124,12,ES_AUTOHSCROLL
RTEXT "URL",IDC_STATIC,173,69,36,8
EDITTEXT IDC_ID3V2_URL,212,67,124,12,ES_AUTOHSCROLL
RTEXT "Encoded by",IDC_STATIC,173,84,36,8
EDITTEXT IDC_ID3V2_ENCODER,212,82,124,12,ES_AUTOHSCROLL
RTEXT "BPM",IDC_STATIC,173,99,36,8
EDITTEXT IDC_ID3V2_BPM,212,97,41,12,ES_AUTOHSCROLL
RTEXT "Track Gain",IDC_STATIC,173,114,36,8
EDITTEXT IDC_TRACK_GAIN,212,112,41,12,ES_AUTOHSCROLL | ES_READONLY
RTEXT "Album Gain",IDC_STATIC,255,114,36,8
EDITTEXT IDC_ALBUM_GAIN,294,112,41,12,ES_AUTOHSCROLL | ES_READONLY
PUSHBUTTON "Copy &to ID3v1",IDC_ID3V2_TO_V1,272,144,62,14
END
IDD_INFO_LYRICS3 DIALOGEX 0, 0, 341, 164
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Lyrics3",-1,0,0,196,70
CONTROL "&Include Lyrics3 tag in file",IDC_LYRICS3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,9,108,10
RTEXT "Title",-1,7,24,36,8
EDITTEXT IDC_LYRICS3_TITLE,46,22,144,12,ES_AUTOHSCROLL | ES_READONLY
RTEXT "Artist",-1,7,39,36,8
EDITTEXT IDC_LYRICS3_ARTIST,46,37,144,12,ES_AUTOHSCROLL | ES_READONLY
RTEXT "Album",-1,7,54,36,8
EDITTEXT IDC_LYRICS3_ALBUM,46,52,144,12,ES_AUTOHSCROLL | ES_READONLY
END
IDD_INFO_APEV2 DIALOGEX 0, 0, 341, 164
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "APEv2",IDC_STATIC,0,0,341,164
CONTROL "&Include APEv2 tag in file",IDC_APEV2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,9,108,10
CONTROL "",IDC_APE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP,6,20,163,136
LTEXT "Name:",IDC_STATIC,176,20,22,8
EDITTEXT IDC_APE_KEY,176,31,158,14,ES_AUTOHSCROLL
LTEXT "Value:",IDC_STATIC,176,47,21,8
EDITTEXT IDC_APE_VALUE,176,57,158,81,ES_MULTILINE | ES_AUTOHSCROLL | ES_OEMCONVERT | ES_WANTRETURN | WS_VSCROLL
PUSHBUTTON "Add New",IDC_APE_ADD,176,142,50,14
PUSHBUTTON "Delete",IDC_APE_DELETE,230,142,50,14
PUSHBUTTON "Delete All",IDC_DELETE_ALL,284,142,50,14
END
IDD_ADVANCED_TAGGING DIALOGEX 0, 0, 226, 122
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "APEv2 and Lyrics3"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "APEv2 Tags",-1,6,6,214,111
CONTROL "Read APEv2 tags",IDC_READ_APEV2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,17,73,10
CONTROL "Modify existing APEv2 tags when updating metadata",IDC_WRITE_APEV2,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,29,181,10
CONTROL "Create new APEv2 tags when adding metadata",IDC_CREATE_APEV2,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,40,165,10
LTEXT "When writing APEv2 headers:",IDC_STATIC_APEV2_HEADER,13,54,96,8
COMBOBOX IDC_APEV2_HEADER_OPTIONS,25,66,166,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "Lyrics3 Tags",-1,6,90,214,27
CONTROL "Read Lyrics3 tags",IDC_READ_LYRICS3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,102,73,10
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_NULLSOFT_MPEG_AUDIO_DECODER_OLD "Nullsoft MPEG Audio Decoder"
IDS_CANNOT_WRITE_STREAMS_TO_DISK "Sorry cannot write streams to disk"
IDS_BUFFER_X "Buffer: %d%%"
IDS_ERROR_SYNCING_TO_STREAM "Error syncing to stream"
IDS_CONNECTING "Connecting"
IDS_NO_VALID_MULTICONNECT_URL "No valid Multiconnect URL"
IDS_REDIRECT_LIMIT_EXCEEDED "Redirect limit exceeded"
IDS_READING_ID3 "Reading ID3"
IDS_STREAM_TERMINATED "Stream terminated"
IDS_STREAM_TEMPORARILY_INTERRUPTED "Stream temporarily interrupted"
END
STRINGTABLE
BEGIN
IDS_NULLSOFT_MPEG_AUDIO_DECODER "Nullsoft MPEG Audio Decoder v%s"
65535 "{CD3EEF98-011C-4213-BC16-3F91C937B9B8}"
END
STRINGTABLE
BEGIN
IDS_NETWORK_RECEIVED_X_BYTES "Network received: %llu bytes\n"
IDS_SERVER "Server: %s\n"
IDS_CONTENT_TYPE "Content-Type: %s\n"
IDS_ULTRAVOX_SYNC "Ultravox sync: %d messages, %d desyncs\n"
IDS_ULTRAVOX_DATA_MESSAGE "Ultravox Data Message: 0x%X\n"
IDS_ULTRAVOX_SID_AVGBR_MAXBR "Ultravox SID/AvgBR/MaxBR: %d/%d/%d\n"
IDS_METADATA_RECEIVED "Metadata received: %d bytes\n"
IDS_METADATA_INTERVAL "Metadata interval: %d bytes\n"
IDS_ID3v2_TAG "ID3v2 tag: %d bytes\n"
IDS_VBR_LEADING_FRAME "VBR leading frame: %d bytes\n"
IDS_STREAM_NAME "Stream name: %s\n"
IDS_CURRENT_TITLE "Current title: %s\n"
IDS_CONTENT_LENGTH "Content length: %d bytes\n"
IDS_SAVING_TO "Saving to: %s\n"
END
STRINGTABLE
BEGIN
IDS_CUSTOM "Custom"
IDS_MONO "Mono"
IDS_STEREO "Stereo"
IDS_3_CHANNEL "3 channel"
IDS_4_CHANNEL "4 channel"
IDS_SURROUND "Surround"
IDS_5_1 "5.1"
IDS_7_1 "7.1"
IDS_ERROR "error"
IDS_NONE "None"
IDS_50_15_MICROSEC "50/15 microsec"
IDS_INVALID "invalid"
IDS_JOINT_STEREO "Joint Stereo"
IDS_2_CHANNEL "2 Channel"
IDS_PAYLOAD_SIZE "Payload Size: %u bytes"
IDS_FORMAT_AAC "\nFormat: AAC"
END
STRINGTABLE
BEGIN
IDS_MPEG2_HE_AAC_IS "\nMPEG-2 HE-AAC (Implicitly Signalled)"
IDS_MPEG4_HE_AAC_IS "\nMPEG-4 HE-AAC (Implicitly Signalled)"
IDS_SAMPLE_RATE_OUTPUT "\nSample Rate: %u (Output: %u)"
IDS_SAMPLE_RATE "\nSample Rate: %u "
IDS_SBR_PRESENT "\nSBR: Present"
IDS_SBR_NOT_PRESENT "\nSBR: Not Present"
IDS_CHANNELS_OUTPUT "\nChannels: %u (Output: %u)"
IDS_CHANNELS "\nChannels: %u"
IDS_MODE_MONO " Mode: Mono"
IDS_MODE_STEREO " Mode: Stereo"
IDS_MODE_PARAMETRIC_STEREO " Mode: Parametric Stereo"
IDS_MODE_DUAL_CHANNEL " Mode: Dual Channel"
IDS_MODE_4_CHANNEL_2_CPE " Mode: 4 Channel 2 CPE"
IDS_MODE_4_CHANNEL_MPEG " Mode: 4 Channel MPEG"
IDS_MODE_5_CHANNEL " Mode: 5 Channel"
IDS_MODE_5_1 " Mode: 5.1"
END
STRINGTABLE
BEGIN
IDS_MODE_6_1 " Mode: 6.1"
IDS_MODE_7_1 " Mode: 7.1"
IDS_BITRATE "\nBitrate: %u"
IDS_AVERAGE_BITRATE "\nBitrate: VBR (%u)"
IDS_HEADER_FOUND_AT_X_BYTES "\nHeader found at: %d bytes"
IDS_LENGTH_X_SECONDS "\nLength: %u seconds"
IDS_PROFILE "\nProfile: %s"
IDS_YES "Yes"
IDS_NO "No"
IDS_ENC_DELAY_ZERO_PADDING "\nEnc Delay: %u, Zero Padding: %u"
IDS_S_LAYER_X "\n%s layer %d"
IDS_X_KBIT "\n%d kbps, %d frames"
IDS_X_KBIT_APPROX "\n%d kbps, approx. %d frames"
IDS_X_KBIT_VBR "\n%d kbps (VBR%s), %d frames"
IDS_X_HZ_S "\n%d Hz %s"
IDS_COPYRIGHTED ", Copyrighted: %s"
END
STRINGTABLE
BEGIN
IDS_ORIGINAL "\nOriginal: %s"
IDS_EMPHASIS ", Emphasis: %s"
IDS_EXT_MP3_SURROUND "\nExtension: MP3 Surround"
IDS_MP3_HAS_BEEN_MODIFIED_NOT_ALL_MAY_BE_CORRECT
"\nMP3 has been modified from its original encoding. Some information may be incorrect."
IDS_MPEG_AUDIO_FILES "MPEG Audio Files ("
END
STRINGTABLE
BEGIN
IDS_MPEG_AUDIO_DECODER_SETTINGS "MPEG Audio Decoder Settings"
IDS_LATIN_1 "Latin-1"
IDS_SYSTEM_LANGUAGE "System Language"
IDS_UNICODE_UTF_16 "Unicode (UTF-16)"
IDS_SELECT_DIRECTORY_TO_SAVE_TO "Select directory to save streamed mp3s"
END
STRINGTABLE
BEGIN
IDS_X_KBIT_ABR "\n%d kbps (ABR), %d frames"
IDS_NAME "Name"
END
STRINGTABLE
BEGIN
IDS_VALUE "Value"
IDS_APEV2_RETAIN_HEADER "Retain existing header"
IDS_APEV2_ADD_HEADER "Add header"
IDS_APEV2_REMOVE_HEADER "Remove header"
IDS_ERROR_SAVING_METADATA "Error saving metadata"
IDS_METADATA_ERROR_READONLY "Cannot save metadata: File is read-only!"
IDS_METADATA_ERROR_OPENING_FILE
"Cannot save metadata: Error opening file."
IDS_METADATA_ERROR_APEV2 "Cannot save metadata: APEv2 tag writing failed."
IDS_METADATA_ERROR_LYRICS3
"Cannot save metadata: Lyrics3 tag writing failed."
IDS_METADATA_ERROR_ID3V1 "Cannot save metadata: ID3v1 tag writing failed."
IDS_METADATA_ERROR_ID3V2 "Cannot save metadata: ID3v2 tag writing failed."
IDS_METADATA_ERROR_UNSPECIFIED "Cannot save metadata: Unspecified error."
IDS_TIMED_OUT "timed out"
IDS_FAMILY_STRING_MP3 "MPEG Layer 3 Audio File"
IDS_FAMILY_STRING_MP2 "MPEG Layer 2 Audio File"
IDS_FAMILY_STRING_MP1 "MPEG Layer 1 Audio File"
END
STRINGTABLE
BEGIN
IDS_FAMILY_STRING_MPEG2_AAC "MPEG-2 Advanced Audio Coding File"
IDS_FAMILY_STRING_DOLBY "Dolby Very Low Bitrate AAC File"
IDS_ABOUT_TEXT "%s\n© 1998-2023 Winamp SA\n\nBuild date: %hs\n\nMPEG Audio Decoding provided by libmpg123"//MPEG Layer-3 audio compression technology\nlicensed by Fraunhofer IIS & THOMSON multimedia.\n\nMPEG-4 AAC decoding licensed by Fraunhofer IIS"
IDS_LENGTH_X_PART_SECONDS "\nLength: %.2f seconds"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#include "version.rc2"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+102
View File
@@ -0,0 +1,102 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29424.173
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_mp3", "in_mp3.vcxproj", "{AEA9FF14-57EC-49AB-BC3A-764A011AC002}"
ProjectSection(ProjectDependencies) = postProject
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
{E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "apev2", "..\apev2\apev2.vcxproj", "{48387E27-2666-4ACF-9C21-AE508C529580}"
ProjectSection(ProjectDependencies) = postProject
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "id3v2", "..\id3v2\id3v2.vcxproj", "{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
ProjectSection(ProjectDependencies) = postProject
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Debug|Win32.ActiveCfg = Debug|Win32
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Debug|Win32.Build.0 = Debug|Win32
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Debug|x64.ActiveCfg = Debug|x64
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Debug|x64.Build.0 = Debug|x64
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Release|Win32.ActiveCfg = Release|Win32
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Release|Win32.Build.0 = Release|Win32
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Release|x64.ActiveCfg = Release|x64
{AEA9FF14-57EC-49AB-BC3A-764A011AC002}.Release|x64.Build.0 = Release|x64
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|Win32.ActiveCfg = Debug|Win32
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|Win32.Build.0 = Debug|Win32
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|x64.ActiveCfg = Debug|x64
{48387E27-2666-4ACF-9C21-AE508C529580}.Debug|x64.Build.0 = Debug|x64
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|Win32.ActiveCfg = Release|Win32
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|Win32.Build.0 = Release|Win32
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|x64.ActiveCfg = Release|x64
{48387E27-2666-4ACF-9C21-AE508C529580}.Release|x64.Build.0 = Release|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Debug|Win32.ActiveCfg = Debug|Win32
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Debug|Win32.Build.0 = Debug|Win32
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Debug|x64.ActiveCfg = Debug|x64
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Debug|x64.Build.0 = Debug|x64
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Release|Win32.ActiveCfg = Release|Win32
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Release|Win32.Build.0 = Release|Win32
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Release|x64.ActiveCfg = Release|x64
{0C7AAFA2-2A78-4B91-99A3-3E866B484ADB}.Release|x64.Build.0 = Release|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
EndGlobalSection
EndGlobal
+386
View File
@@ -0,0 +1,386 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{AEA9FF14-57EC-49AB-BC3A-764A011AC002}</ProjectGuid>
<RootNamespace>in_mp3</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>false</VcpkgEnableManifest>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;AAC_SUPPORT;WIN32;_WINDOWS;_USRDLL;UNICODE_INPUT_PLUGIN;DO_LAYER12;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;AAC_SUPPORT;WIN64;_WINDOWS;_USRDLL;UNICODE_INPUT_PLUGIN;DO_LAYER12;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;AAC_SUPPORT;WIN32;_WINDOWS;_USRDLL;UNICODE_INPUT_PLUGIN;DO_LAYER12;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<GenerateMapFile>false</GenerateMapFile>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>true</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;AAC_SUPPORT;WIN64;_WINDOWS;_USRDLL;UNICODE_INPUT_PLUGIN;DO_LAYER12;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4996;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<DelayLoadDLLs>comctl32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<GenerateMapFile>false</GenerateMapFile>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>true</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<SubSystem>Windows</SubSystem>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\apev2\apev2.vcxproj">
<Project>{48387e27-2666-4acf-9c21-ae508c529580}</Project>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\id3v2\id3v2.vcxproj">
<Project>{0c7aafa2-2a78-4b91-99a3-3e866b484adb}</Project>
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\nsutil\nsutil.vcxproj">
<Project>{dabe6307-f8dd-416d-9dac-673e2decb73f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\replicant\jnetlib\jnetlib.vcxproj">
<Project>{e105a0a2-7391-47c5-86ac-718003524c3d}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\replicant\nu\nu.vcxproj">
<Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\nu\RingBuffer.h" />
<ClInclude Include="..\..\..\Wasabi\api\service\svcs\svc_metatag.h" />
<ClInclude Include="AACFrame.h" />
<ClInclude Include="adts.h" />
<ClInclude Include="adts_vlb.h" />
<ClInclude Include="AlbumArt.h" />
<ClInclude Include="apev2.h" />
<ClInclude Include="api__in_mp3.h" />
<ClInclude Include="config.h" />
<ClInclude Include="CVbriHeader.h" />
<ClInclude Include="DecodeThread.h" />
<ClInclude Include="DXHEAD.H" />
<ClInclude Include="FactoryHelper.h" />
<ClInclude Include="giofile.h" />
<ClInclude Include="id3.h" />
<ClInclude Include="ID3v1.h" />
<ClInclude Include="ID3v2.h" />
<ClInclude Include="ifc_mpeg_stream_reader.h" />
<ClInclude Include="LAMEinfo.h" />
<ClInclude Include="Lyrics3.h" />
<ClInclude Include="main.h" />
<ClInclude Include="Metadata.h" />
<ClInclude Include="MetadataFactory.h" />
<ClInclude Include="MP3Info.h" />
<ClInclude Include="mpegutil.h" />
<ClInclude Include="OFL.h" />
<ClInclude Include="pdtimer.h" />
<ClInclude Include="RawMediaReader.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Stopper.h" />
<ClInclude Include="uvox_3901.h" />
<ClInclude Include="uvox_3902.h" />
<ClInclude Include="WasabiMetadata.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\nu\listview.cpp" />
<ClCompile Include="..\..\..\nu\RingBuffer.cpp" />
<ClCompile Include="AACFrame.cpp" />
<ClCompile Include="adts_vlb.cpp" />
<ClCompile Include="AlbumArt.cpp" />
<ClCompile Include="apev2.cpp" />
<ClCompile Include="config.cpp" />
<ClCompile Include="CVbriHeader.cpp" />
<ClCompile Include="DecodeThread.cpp" />
<ClCompile Include="DXHEAD.C">
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompileAsCpp</CompileAs>
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompileAsCpp</CompileAs>
</ClCompile>
<ClCompile Include="ExtendedInfo.cpp" />
<ClCompile Include="ExtendedRead.cpp" />
<ClCompile Include="giofile.cpp" />
<ClCompile Include="id3.cpp" />
<ClCompile Include="id3dlg.cpp" />
<ClCompile Include="ID3v1.cpp" />
<ClCompile Include="ID3v2.cpp" />
<ClCompile Include="LAMEinfo.cpp" />
<ClCompile Include="Lyrics3.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="Metadata.cpp" />
<ClCompile Include="MetadataFactory.cpp" />
<ClCompile Include="MP3Info.cpp" />
<ClCompile Include="mpegutil.cpp" />
<ClCompile Include="OFL.cpp" />
<ClCompile Include="pdtimer.cpp" />
<ClCompile Include="RawMediaReader.cpp" />
<ClCompile Include="Stopper.cpp" />
<ClCompile Include="titlelist.cpp" />
<ClCompile Include="uvox_3901.cpp" />
<ClCompile Include="uvox_3902.cpp" />
<ClCompile Include="WasabiMetadata.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="in_mp3.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="AACFrame.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="adts_vlb.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AlbumArt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="apev2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CVbriHeader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DecodeThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DXHEAD.C">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ExtendedInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ExtendedRead.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="giofile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="id3.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="id3dlg.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ID3v1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ID3v2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LAMEinfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Lyrics3.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Metadata.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MetadataFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MP3Info.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mpegutil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="OFL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pdtimer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RawMediaReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Stopper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="titlelist.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="uvox_3902.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="uvox_3901.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="WasabiMetadata.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\nu\listview.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\nu\RingBuffer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AACFrame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="adts.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="adts_vlb.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="apev2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AlbumArt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="api__in_mp3.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CVbriHeader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DecodeThread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DXHEAD.H">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FactoryHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="giofile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="id3.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ID3v1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ID3v2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ifc_mpeg_stream_reader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LAMEinfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Lyrics3.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="main.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Metadata.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MetadataFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MP3Info.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mpegutil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="OFL.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pdtimer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RawMediaReader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Stopper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="uvox_3901.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="uvox_3902.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WasabiMetadata.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\nu\RingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\Wasabi\api\service\svcs\svc_metatag.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{21897fc1-e5e6-4baf-8768-1f94870c3daf}</UniqueIdentifier>
</Filter>
<Filter Include="Ressource Files">
<UniqueIdentifier>{cf21f14f-48fa-49b3-bd4e-121aea3d1c61}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{d4950784-f6d6-4b2a-8b50-077f3edbee40}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="in_mp3.rc">
<Filter>Ressource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
+342
View File
@@ -0,0 +1,342 @@
//#define PLUGIN_NAME "Nullsoft MPEG Audio Decoder"
#include "main.h"
#include <time.h>
#include "DecodeThread.h"
#include "api__in_mp3.h"
#include "../Winamp/wa_ipc.h"
#include "../nu/ServiceBuilder.h"
#include "config.h"
#include "AlbumArt.h"
#include "MetadataFactory.h"
#include "../nu/Singleton.h"
#include "RawMediaReader.h"
char lastfn_status[256] = {0};
int lastfn_status_err = 0;
CRITICAL_SECTION g_lfnscs;
CRITICAL_SECTION streamInfoLock;
int lastfn_data_ready;
int config_fastvis=0;
unsigned char config_miscopts=0;
unsigned char allow_sctitles=1;
unsigned char sctitle_format=1;
unsigned char config_eqmode=4,config_http_proxynonport80=1;
unsigned int winampVersion=0x00005010; // default version # to use if winamp version is 5.1 or less (and therefore doesn't have a valid HWND during Init)
char config_http_save_dir[MAX_PATH] = "C:\\";
int config_http_buffersize=64, config_http_prebuffer=40, config_http_prebuffer_underrun=10;
unsigned char config_downmix=0, config_downsample=0, allow_scartwork=1;
int config_max_bufsize_k=128;
int config_gapless=1;
char INI_FILE[MAX_PATH] = {0};
wchar_t lastfn[8192] = {0}; // currently playing file (used for getting info on the current file)
// Used for correcting DSP plug-in pitch changes
int paused = 0; // are we paused?
int m_is_stream = 0;
bool m_is_stream_seekable = true;
volatile int killDecodeThread=0; // the kill switch for the decode thread
HANDLE thread_handle=INVALID_HANDLE_VALUE; // the handle to the decode thread
DWORD WINAPI DecodeThread(LPVOID b); // the decode thread procedure
extern char *getfileextensions();
#include "api/service/waservicefactory.h"
#include "FactoryHelper.h"
// wasabi based services for localisation support
HINSTANCE WASABI_API_LNG_HINST = 0;
HINSTANCE WASABI_API_ORIG_HINST = 0;
api_language *WASABI_API_LNG = 0;
api_application *WASABI_API_APP = 0;
api_config *AGAVE_API_CONFIG = 0;
api_memmgr *WASABI_API_MEMMGR = 0;
AlbumArtFactory albumArtFactory;
MetadataFactory metadataFactory;
static RawMediaReaderService raw_media_reader_service;
static SingletonServiceFactory<svc_raw_media_reader, RawMediaReaderService> raw_factory;
int init()
{
if (!IsWindow(mod.hMainWindow))
return IN_INIT_FAILURE;
winampVersion = (unsigned int)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETVERSION);
mod.service->service_register(&metadataFactory);
mod.service->service_register(&albumArtFactory);
raw_factory.Register(mod.service, &raw_media_reader_service);
ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
ServiceBuild(WASABI_API_LNG, languageApiGUID);
ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
// need to have this initialised before we try to do anything with localisation features
WASABI_API_START_LANG(mod.hDllInstance,InMp3LangGUID);
static wchar_t szDescription[256];
swprintf(szDescription, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_MPEG_AUDIO_DECODER), PLUGIN_VERSION);
mod.description = (char*)szDescription;
InitializeCriticalSection(&g_lfnscs);
InitializeCriticalSection(&streamInfoLock);
mod.UsesOutputPlug|=2;
config_read();
mod.FileExtensions=getfileextensions();
return IN_INIT_SUCCESS;
}
void quit()
{
DeleteCriticalSection(&g_lfnscs);
DeleteCriticalSection(&streamInfoLock);
ServiceRelease(mod.service, AGAVE_API_CONFIG, AgaveConfigGUID);
ServiceRelease(mod.service, WASABI_API_APP, applicationApiServiceGuid);
ServiceRelease(mod.service, WASABI_API_MEMMGR, memMgrApiServiceGuid);
mod.service->service_deregister(&albumArtFactory);
raw_factory.Deregister(mod.service);
}
int g_eq_ok;
int isourfile(const wchar_t *fn)
{
if (!_wcsnicmp(fn,L"uvox://",7)) return 1;
if (!_wcsnicmp(fn,L"icy://",6)) return 1;
if (!_wcsnicmp(fn,L"sc://",5)) return 1;
if (!_wcsnicmp(fn,L"shoutcast://",12)) return 1;
return 0;
}
int m_force_seek=-1;
// called when winamp wants to play a file
int play(const in_char *fn)
{
DWORD thread_id;
lastfn_status_err=0;
paused=0;
g_length=-1000;
decode_pos_ms=0;
seek_needed=m_force_seek;
m_force_seek=-1;
m_is_stream = 0;
m_is_stream_seekable = false;
killDecodeThread=0;
g_sndopened=0;
lastfn_data_ready=0;
lastfn_status[0]=0;
g_bufferstat=0;
g_closeaudio=0;
lstrcpynW(lastfn,fn, 8192);
mod.is_seekable = 0;
mod.SetInfo(0,0,0,0);
g_ds=config_downsample;
g_eq_ok=1;
// launch decode thread
thread_handle = (HANDLE)CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) DecodeThread,NULL,0,&thread_id);
SetThreadPriority(thread_handle, (int)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
return 0;
}
// standard pause implementation
void pause()
{
paused=1;
if (g_sndopened)
mod.outMod->Pause(1);
}
void unpause()
{
paused=0;
if (g_sndopened)
mod.outMod->Pause(0);
}
int ispaused()
{
return paused;
}
// stop playing.
void stop()
{
killDecodeThread=1;
WaitForSingleObject(thread_handle,INFINITE);
CloseHandle(thread_handle);
g_eq_ok=0;
thread_handle = INVALID_HANDLE_VALUE;
g_length=-1000;
lastfn[0]=0;
if (g_closeaudio)
{
g_closeaudio=0;
mod.outMod->Close();
mod.SAVSADeInit();
}
g_sndopened=0;
m_force_seek=-1;
}
// returns length of playing track
int getlength()
{
return g_length;
}
// returns current output position, in ms.
// you could just use return mod.outMod->GetOutputTime(),
// but the dsp plug-ins that do tempo changing tend to make
// that wrong.
int getoutputtime()
{
if (g_bufferstat)
return g_bufferstat;
if (!lastfn_data_ready||!g_sndopened)
return 0;
if (seek_needed!=-1)
return seek_needed;
return decode_pos_ms +
(mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
}
// called when the user releases the seek scroll bar.
// usually we use it to set seek_needed to the seek
// point (seek_needed is -1 when no seek is needed)
// and the decode thread checks seek_needed.
void setoutputtime(int time_in_ms)
{
if (m_is_stream == 0 || (m_is_stream !=0 && m_is_stream_seekable))
{
seek_needed=time_in_ms;
m_force_seek=-1;
}
}
// standard volume/pan functions
void setvolume(int volume)
{
mod.outMod->SetVolume(volume);
}
void setpan(int pan)
{
mod.outMod->SetPan(pan);
}
// this is an odd function. it is used to get the title and/or
// length of a track.
// if filename is either NULL or of length 0, it means you should
// return the info of lastfn. Otherwise, return the information
// for the file in filename.
// if title is NULL, no title is copied into it.
// if length_in_ms is NULL, no length is copied into it.
static int memcmpv(char *d, char v, int l)
{
while (l--)
if (*d++ != v) return 1;
return 0;
}
void eq_set(int on, char data[10], int preamp)
{
int x;
eq_preamp = preamp;
eq_enabled = on;
for (x = 0; x < 10; x ++)
eq_tab[x] = data[x];
// if eq zeroed out, dont use eq
if (eq_enabled && preamp==31 && !memcmpv(data,31,10))
eq_enabled=0;
}
// render 576 samples into buf.
// this function is only used by DecodeThread.
// note that if you adjust the size of sample_buffer, for say, 1024
// sample blocks, it will still work, but some of the visualization
// might not look as good as it could. Stick with 576 sample blocks
// if you can, and have an additional auxiliary (overflow) buffer if
// necessary..
// module definition.
extern In_Module mod =
{
IN_VER_RET, // defined in IN2.H
"nullsoft(in_mp3.dll)",
0, // hMainWindow (filled in by winamp)
0, // hDllInstance (filled in by winamp)
0,
// this is a double-null limited list. "EXT\0Description\0EXT\0Description\0" etc.
0, // is_seekable
1, // uses output plug-in system
config,
about,
init,
quit,
getfileinfo,
id3Dlg,
isourfile,
play,
pause,
unpause,
ispaused,
stop,
getlength,
getoutputtime,
setoutputtime,
setvolume,
setpan,
0,0,0,0,0,0,0,0,0, // visualization calls filled in by winamp
0,0, // dsp calls filled in by winamp
eq_set,
NULL, // setinfo call filled in by winamp
0, // out_mod filled in by winamp
};
// exported symbol. Returns output module.
extern "C"
{
__declspec(dllexport) In_Module * winampGetInModule2()
{
return &mod;
}
}
+123
View File
@@ -0,0 +1,123 @@
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "giofile.h"
#include "dxhead.h"
#include "CVbriHeader.h"
#include "resource.h"
#include "in2.h"
#define PLUGIN_VERSION L"4.6"
extern In_Module mod;
extern char INI_FILE[MAX_PATH];
extern int g_length;
extern int lastfn_data_ready;
extern int id3Dlg(const wchar_t *fn, HWND hwnd);
extern int getlength();
extern void getfileinfo(const wchar_t *filename, wchar_t *title, int *length_in_ms);
extern int config_max_bufsize_k;
extern int config_gapless;
extern int config_fastvis;
extern unsigned char config_miscopts;
extern unsigned char config_downmix, config_downsample;
extern int config_http_buffersize, config_http_prebuffer, config_http_prebuffer_underrun;
extern unsigned char allow_sctitles,sctitle_format, allow_scartwork;
extern char config_http_save_dir[MAX_PATH];
extern wchar_t lastfn[8192]; // currently playing file (used for getting info on the current file)
extern char g_stream_title[256];
extern char lastfn_status[256];
extern int lastfn_status_err;
extern int paused; // are we paused?
extern void config_read();
extern void about(HWND hwndParent);
extern void strmBuf_Quit();
extern int strmBuf_Start(char *streamurl, int num_bytes, int pre_buffer_top, int pre_buffer_bottom);
extern int strmBuf_Read(void *data, int bytes_requested);
extern void config(HWND hwndParent);
extern volatile int killDecodeThread;
extern unsigned char eq_preamp;
extern unsigned char eq_enabled;
extern unsigned char eq_tab[10];
extern unsigned char config_eqmode;
extern unsigned int winampVersion;
extern int g_eq_ok;
extern CRITICAL_SECTION g_lfnscs;
extern CRITICAL_SECTION streamInfoLock;
#if !defined(__alpha) && !defined(_WIN64)
static __inline long float_to_long(double t)
{
long r;
__asm fld t
__asm fistp r
return r;
}
#else
#define float_to_long(x) ((long)( x ))
#endif
extern void processMetaDataC(char *data, int len, int msgId );
enum
{
UVOX_METADATA_STYLE_AOLRADIO = 0,
UVOX_METADATA_STYLE_SHOUTCAST = 1,
UVOX_METADATA_STYLE_SHOUTCAST2 = 2,
UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK = 3,
UVOX_METADATA_STYLE_SHOUTCAST2_ARTWORK_PLAYING = 4,
};
typedef struct {
void *Next;
int style;
long timer;
char title[16384];
int part;
int total_parts;
int part_len;
int type;
} TitleType;
#define TITLELISTTYPE TitleType
extern TITLELISTTYPE *TitleLinkedList;
extern TITLELISTTYPE TitleListTerminator;
extern void initTitleList(void);
extern TITLELISTTYPE *newTitleListEntry(void);
extern void removeTitleListEntry(TITLELISTTYPE *Entry);
extern void clearTitleList(void);
char *GetUltravoxUserAgent();
char *GetUserAgent();
void w9x_lstrcpynW(wchar_t *dest, const wchar_t *src, int maxLen);
// maximum acceptable deviance between LAME header bytesize and real filesize (minus id3 tag)
// has to be large enough to accomodate unknown tags (APE, lyrics3)
const int MAX_ACCEPTABLE_DEVIANCE = 16384;
void get_extended_info(const wchar_t *fn, int *len);
#define UVOX_3901_LEN 32768
void ConvertTryUTF8(const char *in, wchar_t *out, size_t outlen);
#ifdef AAC_SUPPORT
extern char config_extlist_aac[129];
#define config_extlist config_extlist_aac
#else
extern char config_extlist[129];
#endif
extern int m_force_seek;
extern CGioFile *g_playing_file;
int _r_i(char *name, int def);
void _w_i(char *name, int d);
+44
View File
@@ -0,0 +1,44 @@
#include "vlb_sub/aacdecoder.h"
#include "vlbout.h"
void CStreamInfo::setSampleRate()
{
SetSamplingRate(CChannelInfo::SamplingRateFromIndex(GetSamplingRateIndex ()));
}
#ifndef ACTIVEX_CONTROL
//methods used by in_mp4
extern "C"
{
__declspec( dllexport ) int aacGetBitBuffer()
{
return (int) new CBitBuffer;
}
__declspec( dllexport ) int aacGetDecoderInterfaces(CAacDecoder **decoder, CBitBuffer *buf, CStreamInfo **info, VLBOut **dataout)
{
*decoder=new CAacDecoder(*buf);
*info=new CStreamInfo;
*dataout=new VLBOut();
return 1;
}
__declspec( dllexport ) void aacDeleteBitBuffer(CBitBuffer *bitBuffer)
{
if (bitBuffer)
delete bitBuffer;
}
__declspec( dllexport ) void aacDeleteDecoderInterfaces(CAacDecoder *decoder, CStreamInfo *info, VLBOut *dataout)
{
if (decoder)
delete decoder;
if (info)
delete info;
if (dataout)
delete dataout;
}
}
#endif
+372
View File
@@ -0,0 +1,372 @@
#include "DecodeThread.h"
#include "main.h"
// benski> cut some old shit
// this code would take the filterbank coefficients to get an approximate spectrum
// and modify the coefficients to do a quick&easy EQ
// it's been off by default for quite a few versions (i think starting with 5.12)
// but not I just yanked it out. cause none of us have 486SX's any more
static float eq_lookup1[64]={
4.000000f,3.610166f,3.320019f,3.088821f,2.896617f,
2.732131f,2.588368f,2.460685f,2.345845f,2.241498f,
2.145887f,2.057660f,1.975760f,1.899338f,1.827707f,
1.760303f,1.696653f,1.636363f,1.579094f,1.524558f,
1.472507f,1.422724f,1.375019f,1.329225f,1.285197f,
1.242801f,1.201923f,1.162456f,1.124306f,1.087389f,
1.051628f,1.016951f,0.983296f,0.950604f,0.918821f,
0.887898f,0.857789f,0.828454f,0.799853f,0.771950f,
0.744712f,0.718108f,0.692110f,0.666689f,0.641822f,
0.617485f,0.593655f,0.570311f,0.547435f,0.525008f,
0.503013f,0.481433f,0.460253f,0.439458f,0.419035f,
0.398970f,0.379252f,0.359868f,0.340807f,0.322060f,
0.303614f,0.285462f,0.267593f,0.250000
};
static float eq_lookup2[64] = {
2.00000000f, 1.96825397f, 1.93650794f, 1.90476191f, 1.87301588f,
1.84126985f, 1.80952382f, 1.77777779f, 1.74603176f, 1.71428573f,
1.68253970f, 1.65079367f, 1.61904764f, 1.58730161f, 1.55555558f,
1.52380955f, 1.49206352f, 1.46031749f, 1.42857146f, 1.39682543f,
1.36507940f, 1.33333337f, 1.30158734f, 1.26984131f, 1.23809528f,
1.20634925f, 1.17460322f, 1.14285719f, 1.11111116f, 1.07936513f,
1.04761910f, 1.01587307f, 0.98412699f, 0.95238096f, 0.92063493f,
0.88888890f, 0.85714287f, 0.82539684f, 0.79365081f, 0.76190478f,
0.73015875f, 0.69841272f, 0.66666669f, 0.63492066f, 0.60317463f,
0.57142860f, 0.53968257f, 0.50793654f, 0.47619048f, 0.44444445f,
0.41269842f, 0.38095239f, 0.34920636f, 0.31746033f, 0.28571430f,
0.25396827f, 0.22222222f, 0.19047619f, 0.15873016f, 0.12698413f,
0.09523810f, 0.06349207f, 0.03174603f, 0.00000000
};
unsigned char eq_preamp = 0;
unsigned char eq_enabled = 0;
unsigned char eq_tab[10] = {0};
float g_vis_table[2][2][32][18] = {0};
void mp3GiveVisData(float vistable[2][32][18],int gr, int nch)
{
if (g_vis_enabled)
{
memcpy(&g_vis_table[gr][0][0][0],&vistable[0][0][0],sizeof(float)*32*18*nch);
}
}
void mp2Equalize(float *xr, int nch, int srate, int nparts)
{
if (!g_eq_ok || !(mod.UsesOutputPlug & 2)) return;
if (!eq_enabled) return;
float *eq_lookup = (config_eqmode&1)?eq_lookup2:eq_lookup1;
float preamp = eq_lookup[eq_preamp];
int offs[11] = { 0,1,2,3,4,5,6,9,15,18,32};
int scale_offs[11] = {0};
int x;
unsigned char eqt[12] = {0};
memcpy(eqt+1,eq_tab,10);
eqt[0]=eqt[1];
eqt[11]=eqt[10];
for (x = 0; x < 11; x ++)
{
scale_offs[x] = float_to_long( ((float) offs[x] / (float) srate * 44100.0));
if (scale_offs[x] > 32) scale_offs[x] = 32;
}
{
if (nch == 1)
{
register int i;
for (i = 0; i < 10; i ++)
{
register int x=scale_offs[i];
register int t=scale_offs[i+1];
float d = eq_lookup[(int)eqt[i]]*preamp;
float dd = (eq_lookup[(int)eqt[i+1]]*preamp-d)/(float)(t-x);
if (dd < 0.000000001f && dd > -0.000000001f) dd = 0.000000001f;
while (x < t)
{
register float *p = xr+x;
int e=nparts;
while (e--)
{
*(p) *= d;
p+=32;
}
p += 32*(18-nparts);
d += dd;
x++;
}
}
}
else
{
register int i;
for (i = 0; i < 10; i ++)
{
register int x=scale_offs[i];
register int t=scale_offs[i+1];
float d = eq_lookup[(int)eqt[i]]*preamp;
float dd = (eq_lookup[(int)eqt[i+1]]*preamp-d)/(float)(t-x);
if (dd < 0.000000001f && dd > -0.000000001f) dd = 0.000000001f;
while (x < t)
{
register float *p = xr+x;
int e=nparts;
while (e--)
{
*(p+32*18) *= d;
*(p) *= d;
p+=32;
}
p += 32*(18-nparts);
d += dd;
x++;
}
}
}
}
}
void mp3Equalize(float *xr, int nch, int srate)
{
if (!g_eq_ok || !(mod.UsesOutputPlug & 2)) return;
if (!eq_enabled) return;
float *eq_lookup = (config_eqmode&1)?eq_lookup2:eq_lookup1;
float preamp = eq_lookup[eq_preamp];
static int scale_offs[11];
static int lrate;
unsigned char eqt[12] = {0};
memcpy(eqt+1,eq_tab,10);
eqt[0]=eqt[1];
eqt[11]=eqt[10];
if (lrate!=srate)
{
lrate=srate;
for (int x = 0; x < 11; x ++)
{
int offs[11] = { 0,2,4, 9,16, 30, 63, 95,153,308, 576};
scale_offs[x] = float_to_long( ((float) offs[x] / (float) srate * 44100.0));
if (scale_offs[x] > 576) scale_offs[x] = 576;
}
}
{
if (nch == 1)
{
register float *p = xr;
register float d = eq_lookup[eqt[0]]*preamp;
register int i = 0;
for (i = 0; i < 10; i ++)
{
register int x=scale_offs[i];
register int t=scale_offs[i+1];
register float dd = (eq_lookup[eqt[i+1]]*preamp-d)/(float)(t-x);
while (x++ < t)
{
*(p++) *= d;
d += dd;
}
}
}
else
{
register float *p = xr;
register int i;
for (i = 0; i < 10; i ++)
{
register int x=scale_offs[i];
register int t=scale_offs[i+1];
float d = eq_lookup[(int)eqt[i]]*preamp;
float dd = (eq_lookup[(int)eqt[i+1]]*preamp-d)/(float)(t-x);
if (dd < 0.000000001f && dd > -0.000000001f) dd = 0.000000001f;
while (x++ < t)
{
*(p+32*18) *= d;
*(p++) *= d;
d += dd;
}
}
}
}
}
void genOsc(char *tempdata, short *samples, int len)
{
float d = 0.0f, dd = len/(75.0f*2.0f);
short int *sbuf = samples;
int x,y=0;
signed char *c = (signed char *) tempdata;
for (x = 0; x < 75; x ++)
{
float q=0;
int td = float_to_long((d+=dd));
for (; y < td; y ++)
q += *sbuf++;
q *= (32.0f/(dd*65536.0f));
*c++ = (signed char) float_to_long(q);
}
}
void genSpec(char *tempdata, float *xr, int nch)
{
static int offsets[76] =
{
0,1,2,3,4,5,7,8,9,10,12,13,15,16,18,20,21,23,25,27,29,31,33,36,38,41,43,46,48,51,
54,57,60,64,67,71,74,78,82,86,91,95,100,105,109,115,120,126,131,137,144,150,157,
164,171,178,186,194,203,211,220,230,239,250,260,271,282,294,306,319,332,345,360,
374,389,576
};
{
for (int x = 0; x < 75; x++)
{
float sum = 0.0;
int z;
int sx = offsets[x];
int ex = offsets[x+1];
if (nch == 2)
{
float *p = &xr[0];
int w=32*18;
for (z = sx; z < ex; z ++)
{
register float t1=p[z], t2=p[w+z];
if (t1 <0.0) t1=-t1;
if (t2<0.0f) t2=-t2;
sum += (t1+t2) * 0.5f;
}
}
else
{
float *p = &xr[0];
for (z = sx; z < ex; z ++)
{
register float t=p[z];
if (t < 0.0) t=-t;
sum += t;
}
}
sum *= 1.0f + (x) * 12.0f / (ex-sx) ;
sum *= 1.8f/24000.0f;
if (sum < 0.0) sum = 0.0;
if (sum > 255.0) sum = 255.0;
tempdata[x] = (unsigned char) float_to_long(sum);
}
}
}
void do_layer3_vis(short *samples, float *xr, int nch, int ts)
{
int vis_waveNch;
int vis_specNch;
int csa = mod.SAGetMode();
int is_vis_running = mod.VSAGetMode(&vis_specNch,&vis_waveNch);
static char tempdata[75*2];
int len=32*18*nch;
if (is_vis_running)
{
char data[576*4] = {0};
int data_offs=0;
int x;
if (nch == 1 && vis_specNch > 0)
{
float *specdata = xr;
int y;
for (y=0; y < 576; y++)
{
float p = *specdata++ / 24.0f;
if (p < 0.0) p = -p;
if (p > 255.0) p = 255.0;
data[data_offs++] = (unsigned char) float_to_long(p);
}
if (vis_specNch == 2)
{
memcpy(data+data_offs,data+data_offs-576,576);
data_offs += 576;
}
}
else if (vis_specNch == 2)
{
for (x = 0; x < 2; x ++)
{
float *specdata = &xr[x*32*18];
for (int y=0; y < 576; y++)
{
float p = *specdata++ / 24.0f;
if (p < 0.0) p = -p;
if (p > 255.0) p = 255.0;
data[data_offs++] = (unsigned char) float_to_long(p);
}
}
}
else if (vis_specNch == 1)
{
float *specdata = &xr[0];
int y;
for (y = 0; y < 576; y++)
{
register float p1=specdata[0],p2=specdata[32*18],p;
if (p1 < 0.0) p1=-p1;
if (p2 < 0.0) p2=-p2;
p = (p1+p2)/ 48.0f;
specdata++;
if (p > 255.0) p = 255.0;
data[data_offs++] = (unsigned char) float_to_long(p);
}
} // end of spectrum code
if (nch == 1 && vis_waveNch > 0)
{
for (x = 0; x < 576; x++)
{
data[data_offs++] = ((samples[x])>>8);
}
if (vis_waveNch == 2)
{
memcpy(data+data_offs,data+data_offs-576,576);
data_offs += 576;
}
}
else if (vis_waveNch == 2)
{
for (x = 0; x < 2; x ++)
{
int y;
for (y = 0; y < 576; y ++ )
{
data[data_offs++] = ((samples[y*2+x])>>8);
}
}
}
else if (vis_waveNch == 1)
{
int x;
for (x = 0; x < 576; x ++)
{
data[data_offs++] = ((int)samples[x*2]+(int)samples[x*2+1])>>9;
}
}
mod.VSAAdd(data,ts);
}
if (csa==4)
{
tempdata[0] = 0;
tempdata[1] = 0;
mod.SAAdd(tempdata,ts,4);
}
else if (csa == 3)
{
genSpec(tempdata,xr,nch);
genOsc(tempdata+75,samples,len);
mod.SAAdd(tempdata,ts,0x80000003);
}
else if (csa == 2)
{
genOsc(tempdata,samples,len);
mod.SAAdd(tempdata,ts,2);
}
else if (csa == 1) {
genSpec(tempdata,xr,nch);
mod.SAAdd(tempdata,ts,1);
}
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef NULLSOFT_MPEGUTILH
#define NULLSOFT_MPEGUTILH
extern float g_vis_table[2][2][32][18];
void do_layer3_vis(short *samples, float *xr, int nch, int ts);
void mp3Equalize(float *xr, int nch, int srate);
void mp2Equalize(float *xr, int nch, int srate, int nparts);
void mp3GiveVisData(float vistable[2][32][18],int gr, int nch);
#endif
+24
View File
@@ -0,0 +1,24 @@
#include "pdtimer.h"
__int64 pdReadResolution(void)
{
__int64 myfeq;
LARGE_INTEGER feq;
QueryPerformanceFrequency( &feq);
myfeq = feq.QuadPart;
return myfeq;
}
__int64 pdReadTimer(void)
{
__int64 mynow;
LARGE_INTEGER now;
QueryPerformanceCounter( &now );
mynow = now.QuadPart;
return mynow;
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef NULLSOFT_PDTIMERH
#define NULLSOFT_PDTIMERH
#include <windows.h>
__int64 pdReadResolution(void);
__int64 pdReadTimer(void);
#endif
+16
View File
@@ -0,0 +1,16 @@
// proxydt.h
#ifndef PROXYDT_H
#define PROXYDT_H
#include <string>
#include <stdio.h>
#include <atlbase.h>
char* detectBrowserProxy();
char* DetectIEProxy();
char* DetectNS4Proxy();
char* DetectNS6Proxy();
#endif
+253
View File
@@ -0,0 +1,253 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by script1.rc
//
#define IDS_NULLSOFT_MPEG_AUDIO_DECODER_OLD 0
#define IDS_CANNOT_WRITE_STREAMS_TO_DISK 1
#define IDS_BUFFER_X 2
#define IDC_ID3_REMOVE 3
#define IDC_ID3V1_REMOVE 3
#define IDC_REVERTTAG 3
#define IDS_ERROR_SYNCING_TO_STREAM 3
#define IDC_ID3V2_REMOVE 4
#define IDS_CONNECTING 4
#define IDC_ID3V1_SAVE 5
#define IDS_NO_VALID_MULTICONNECT_URL 5
#define IDC_ID3_REMOVE_ALL 6
#define IDS_REDIRECT_LIMIT_EXCEEDED 6
#define IDC_ID3V1_TO_V2 7
#define IDS_READING_ID3 7
#define IDC_ID3V2_SAVE 8
#define IDS_STREAM_TERMINATED 8
#define IDC_ID3V2_TO_V1 9
#define IDS_STREAM_TEMPORARILY_INTERRUPTED 9
#define IDC_ID3V2_STOP 10
#define IDS_NETWORK_RECEIVED_X_BYTES 16
#define IDS_SERVER 17
#define IDS_CONTENT_TYPE 18
#define IDS_ULTRAVOX_SYNC 19
#define IDS_ULTRAVOX_DATA_MESSAGE 20
#define IDS_ULTRAVOX_SID_AVGBR_MAXBR 21
#define IDS_METADATA_RECEIVED 22
#define IDS_METADATA_INTERVAL 23
#define IDS_ID3v2_TAG 24
#define IDS_VBR_LEADING_FRAME 25
#define IDS_STREAM_NAME 26
#define IDS_CURRENT_TITLE 27
#define IDS_CONTENT_LENGTH 28
#define IDS_SAVING_TO 29
#define IDS_CUSTOM 32
#define IDS_MONO 33
#define IDS_STEREO 34
#define IDS_3_CHANNEL 35
#define IDS_4_CHANNEL 36
#define IDS_SURROUND 37
#define IDS_5_1 38
#define IDS_7_1 39
#define IDS_ERROR 40
#define IDS_NONE 41
#define IDS_50_15_MICROSEC 42
#define IDS_INVALID 43
#define IDS_JOINT_STEREO 44
#define IDS_2_CHANNEL 45
#define IDS_PAYLOAD_SIZE 46
#define IDS_FORMAT_AAC 47
#define IDS_MPEG2_HE_AAC_IS 48
#define IDS_MPEG4_HE_AAC_IS 49
#define IDS_SAMPLE_RATE_OUTPUT 50
#define IDS_SAMPLE_RATE 51
#define IDS_SBR_PRESENT 52
#define IDS_SBR_NOT_PRESENT 53
#define IDS_CHANNELS_OUTPUT 54
#define IDS_CHANNELS 55
#define IDS_MODE_MONO 56
#define IDS_MODE_STEREO 57
#define IDS_MODE_PARAMETRIC_STEREO 58
#define IDS_MODE_DUAL_CHANNEL 59
#define IDS_MODE_4_CHANNEL_2_CPE 60
#define IDS_MODE_4_CHANNEL_MPEG 61
#define IDS_MODE_5_CHANNEL 62
#define IDS_MODE_5_1 63
#define IDS_MODE_6_1 64
#define IDS_MODE_7_1 65
#define IDS_BITRATE 66
#define IDS_AVERAGE_BITRATE 67
#define IDS_HEADER_FOUND_AT_X_BYTES 68
#define IDS_LENGTH_X_SECONDS 69
#define IDS_PROFILE 70
#define IDS_YES 71
#define IDS_NO 72
#define IDS_ENC_DELAY_ZERO_PADDING 73
#define IDS_S_LAYER_X 74
#define IDS_X_KBIT 75
#define IDS_X_KBIT_APPROX 76
#define IDS_X_KBIT_VBR 77
#define IDS_X_HZ_S 78
#define IDS_COPYRIGHTED 79
#define IDS_ORIGINAL 80
#define IDS_EMPHASIS 81
#define IDS_EXT_MP3_SURROUND 82
#define IDS_MP3_HAS_BEEN_MODIFIED_NOT_ALL_MAY_BE_CORRECT 83
#define IDS_UPDATING_FILE 84
#define IDS_CANNOT_MODIFY_TAG_READ_ONLY 85
#define IDS_CANNOT_INSERT_ID3v2_TAG_DRIVE_FULL 86
#define IDS_CANNOT_INSERT_ID3v2_TAG_STOP_PLAYBACK 87
#define IDS_CANNOT_INSERT_ID3v2_TAG_READ_ONLY 88
#define IDS_UPDATING_FILE_REMOVING_TAG 89
#define IDS_CANNOT_REMOVE_ID3v2_TAG_DRIVE_FULL 90
#define IDS_CANNOT_REMOVE_ID3v2_TAG_STOP_TRY_AGAIN 91
#define IDS_CANNOT_REMOVE_ID3v2_TAG_READ_ONLY 92
#define IDS_CANNOT_WRITE_ID3v1_TAG 93
#define IDS_CANNOT_REMOVE_ID3v1_TAG 94
#define IDS_MPEG_AUDIO_FILES 95
#define IDS_MPEG_AUDIO_DECODER_SETTINGS 96
#define IDS_LATIN_1 97
#define IDS_SYSTEM_LANGUAGE 98
#define IDS_UNICODE_UTF_16 99
#define IDS_SELECT_DIRECTORY_TO_SAVE_TO 100
#define ID_YES 101
#define IDD_PREFS 103
#define IDD_OUTPUT 104
#define IDD_STREAM 115
#define IDD_HTTP 177
#define IDD_TAGOPTS 179
#define IDD_HTTPAUTH 182
#define IDD_INFO_ID3V1 186
#define IDD_INFO_ID3V2 187
#define IDD_INFO_LYRICS3 188
#define IDS_X_KBIT_ABR 189
#define IDD_INFO_APEV2 189
#define IDD_ADVANCED_TAGGING 190
#define IDS_NAME 191
#define IDS_VALUE 192
#define IDS_APEV2_RETAIN_HEADER 193
#define IDS_APEV2_ADD_HEADER 194
#define IDS_APEV2_REMOVE_HEADER 195
#define IDS_ERROR_SAVING_METADATA 196
#define IDS_METADATA_ERROR_READONLY 197
#define IDS_METADATA_ERROR_OPENING_FILE 198
#define IDS_METADATA_ERROR_APEV2 199
#define IDS_METADATA_ERROR_LYRICS3 200
#define IDS_METADATA_ERROR_ID3V1 201
#define IDS_METADATA_ERROR_ID3V2 202
#define IDS_METADATA_ERROR_UNSPECIFIED 203
#define IDS_TIMED_OUT 204
#define IDS_FAMILY_STRING_MP3 205
#define IDS_FAMILY_STRING_MP2 206
#define IDS_FAMILY_STRING_MP1 207
#define IDS_FAMILY_STRING_MPEG2_AAC 208
#define IDS_FAMILY_STRING_DOLBY 209
#define IDS_ABOUT_STRING 210
#define IDS_ABOUT_TEXT 210
#define IDS_LENGTH_X_PART_SECONDS 211
#define IDC_FASTL3EQ 1000
#define IDC_BUFFERS_NUMBUFS 1001
#define IDC_FASTL12EQ 1002
#define IDC_ID3V1 1003
#define IDC_ID3V2 1004
#define IDC_16BIT 1005
#define IDC_PREBUFSLIDER 1011
#define IDC_PREBUFSLIDER2 1012
#define IDC_STEREO 1046
#define IDC_REVSTEREO 1048
#define IDC_FULLRATE 1049
#define IDC_HALFRATE 1050
#define IDC_QRATE 1051
#define IDC_PREFS_PRIORITY_DECODE 1076
#define IDC_ID3_TITLE 1078
#define IDC_ID3_ARTIST 1079
#define IDC_ID3_ALBUM 1080
#define IDC_ID3_COMMENT 1081
#define IDC_ID3_YEAR 1082
#define IDC_ID3_GENRE 1083
#define IDC_ID3V2_TITLE 1086
#define IDC_ID3V2_ARTIST 1087
#define IDC_ID3V2_ALBUM 1088
#define IDC_ID3V2_YEAR 1089
#define IDC_ID3V2_GENRE 1090
#define IDC_ID3V2_COMMENT 1091
#define IDC_ID3V2_COMPOSER 1092
#define IDC_ID3V2_MARTIST 1093
#define IDC_ID3V2_RECORD 1094
#define IDC_ID3V2_URL 1095
#define IDC_ID3V2_ENCODER 1096
#define IDC_ID3V2_TRACK 1097
#define IDC_ID3V11_TRACK 1098
#define IDC_BPM 1098
#define IDC_ID3V2_BPM 1098
#define IDC_ID3V2_ALBUM_ARTIST 1099
#define IDC_ID3V2_ENCODER2 1100
#define IDC_ID3V2_DISC 1100
#define IDC_ID3V2_ENCODER3 1101
#define IDC_ID3V2_PUBLISHER 1101
#define IDC_RADIO1 1106
#define IDC_RADIO2 1107
#define IDC_CHECK1 1108
#define IDC_STATUS 1109
#define IDC_SC_ARTWORK 1109
#define IDC_CHECK2 1110
#define IDC_URL 1111
#define IDC_BUTTON2 1112
#define IDC_ID3FORMAT 1127
#define IDC_NORMFORMAT 1128
#define IDC_BUFMAX 1136
#define IDC_CHECK3 1138
#define IDC_ID3V2_STATUS_TEXT 1139
#define IDC_EASTER 1143
#define IDC_USEID3 1145
#define IDC_EDIT1 1146
#define IDC_BUTTON1 1147
#define IDC_TRACK_GAIN 1147
#define IDC_REALM 1148
#define IDC_CHECK5 1150
#define IDC_READ_LYRICS3 1150
#define IDC_WRITE_LOCAL 1151
#define IDC_READ_APEV2 1151
#define IDC_WRITE_UTF16 1152
#define IDC_WRITE_LATIN 1153
#define IDC_READ_LATIN 1154
#define IDC_READ_LOCAL 1155
#define IDC_WRITE_ID3V1 1156
#define IDC_CHECK7 1157
#define IDC_WRITE_ID3V2 1157
#define IDC_READ_ID3V1 1158
#define IDC_READ_ID3V2 1159
#define IDC_24BIT 1160
#define IDC_WRITE_APEV2 1160
#define IDC_CREATE_ID3V1 1160
#define IDC_SURROUND 1161
#define IDC_EDIT_REPLAYGAIN 1162
#define IDC_CREATE_ID3V2 1162
#define IDC_ALBUM_GAIN 1165
#define IDC_COMBO1 1168
#define IDC_COMBO2 1169
#define IDC_LYRICS3_TITLE 1169
#define IDC_LYRICS3_ARTIST 1170
#define IDC_LYRICS3_ALBUM 1171
#define IDC_LYRICS3V2 1172
#define IDC_LYRICS3 1172
#define IDC_APEV2 1173
#define IDC_APELIST 1177
#define IDC_APE_LIST 1177
#define IDC_APE_KEY 1178
#define IDC_DELETE_ALL 1179
#define IDC_APE_VALUE 1180
#define IDC_APE_ADD 1181
#define IDC_APE_DELETE 1182
#define IDC_CREATE_APEV2 1183
#define IDC_STATIC_APEV2_HEADER 1184
#define IDC_APEV2_HEADER_OPTIONS 1185
#define IDC_RATING_EMAIL 1186
#define IDC_RATING_EMAIL_RESET 1187
#define IDS_NULLSOFT_MPEG_AUDIO_DECODER 65534
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 212
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1188
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+953
View File
@@ -0,0 +1,953 @@
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "tagz.h"
#ifdef TAGZ_UNICODE
#define _TX(X) L##X
#define t_strdup _wcsdup
#define t_strlen wcslen
#define t_strnicmp _wcsnicmp
#define t_strtoul wcstoul
#define t_stricmp _wcsicmp
#define t_strstr wcsstr
#define sprintf swprintf
#else
#define _TX(X) X
#define t_strdup _strdup
#define t_strlen strlen
#define t_strnicmp _strnicmp
#define t_strtoul strtoul
#define t_stricmp _stricmp
#define t_strstr strstr
#endif
int t_atoi(T_CHAR * c)
{
if (c[0]=='-') return -(int)t_strtoul(c+1,0,10);
else return (int)t_strtoul(c,0,10);
}
#define TABSIZE(x) (sizeof(x)/sizeof(x[0]))
/*
char * strndup(char * p1,UINT n)
{
char * r=(char*)malloc(n+1);
if (r)
{
memcpy(r,p1,n);
r[n]=0;
}
return n;
}
*/
class String
{
private:
T_CHAR * data;
UINT size, used;
public:
String() {data=0;size=0;used=0;}
void AddChar(T_CHAR c)
{
if (!data)
{
data=(T_CHAR*)malloc((size=512)*sizeof(T_CHAR));
used=0;
}
else if (size==used)
{
UINT old_size = size;
T_CHAR * old_data = data;
size<<=1;
data=(T_CHAR*)realloc((char*)data,size*sizeof(T_CHAR));
if (!data)
{
size = old_size;
data = old_data;
return;
}
}
if (data) data[used++]=c;
}
void AddInt(int i)
{
T_CHAR foo[16];
sprintf(foo,_TX("%i"),i);
AddString(foo);
}
void AddString(const T_CHAR * z)
{
while(*z) {AddChar(*z);z++;}
}
void AddString(String & s)
{
AddString(s.Peek());
}
~String()
{
if (data) free(data);
}
T_CHAR * GetBuf()
{
if (!data) return t_strdup(_TX(""));
T_CHAR * r=(T_CHAR*)realloc(data,(used+1)*sizeof(T_CHAR));
r[used]=0;
data=0;
return r;
}
T_CHAR operator[](UINT i)
{
if (!data || i>=used) return 0;
else return data[i];
}
UINT Len() {return data ? used : 0;}
void Reset()
{
if (data) {free(data);data=0;}
}
const T_CHAR * Peek()
{
AddChar(0);
used--;
return data;
}
T_CHAR * _strdup()
{
return ::t_strdup(Peek());
}
};
static int separator(T_CHAR x)
{
if (!x || x==' ') return 1;
if (x=='\'' || x=='_') return 0;
#ifdef TAGZ_UNICODE
return !iswalnum(x);
#else
return !isalnum(x);
#endif
}
static int sepcmp(T_CHAR* src,T_CHAR* val)
{
UINT l=t_strlen(val);
return !t_strnicmp(src,val,l) && separator(src[l]);
}
static char roman_num[]=
{
'I','V','X','L','C','D','M'
};
static int is_roman(T_CHAR * ptr)//could be more smart i think
{
if (ptr[0]==']' && ptr[1]=='[' && separator(ptr[2])) return 1;
while(!separator(*ptr))
{
UINT n;
bool found=0;
for(n=0;n<TABSIZE(roman_num);n++)
{
if (*ptr==roman_num[n]) {found=1;break;}
}
if (!found) return 0;
ptr++;
}
return 1;
}
static int need_full(T_CHAR* ptr)
{
if (is_roman(ptr)) return 1;
if (sepcmp(ptr,_TX("RPG"))) return 1;
while(!separator(*ptr))
{
if (*ptr<='0' || *ptr>='9') return 0;
ptr++;
}
return 1;
}
class VarList
{
private:
typedef struct tagVAR
{
tagVAR * next;
T_CHAR * name;
T_CHAR * value;
} VAR;
VAR * vars;
public:
VarList() {vars=0;}
~VarList()
{
VAR * p=vars;
while(p)
{
VAR *n=p->next;
free(p->name);
free(p->value);
delete p;
p=n;
}
}
T_CHAR * Get(T_CHAR * name)
{
VAR * p=vars;
while(p)
{
if (!t_stricmp(name,p->name)) return p->value;
p=p->next;
}
return 0;
}
void Put(T_CHAR * name,T_CHAR* value)
{
VAR * p=vars;
while(p)
{
if (!t_stricmp(name,p->name))
{
free(p->value);
p->value=t_strdup(value);
return;
}
p=p->next;
}
p=new VAR;
p->next=vars;
vars=p;
p->value=t_strdup(value);
p->name=t_strdup(name);
}
};
typedef void (*TEXTFUNC)(UINT n_src,T_CHAR **src,UINT*,String &out,VarList & vars);
#define MAKEFUNC(X) static void X(UINT n_src,T_CHAR ** src,UINT *found_src,String &out,VarList &vars)
/*
void Blah(UINT n_src,T_CHAR ** src,UINT*,String &out)
{
out.AddString("blah");
}
void Nop(UINT n_src,T_CHAR ** src,UINT *,String &out)
{
UINT n;
for(n=0;n<n_src;n++) out.AddString(src[n]);
}
*/
MAKEFUNC(Get)
{
if (n_src>=1)
{
T_CHAR * p=vars.Get(src[0]);
if (p) out.AddString(p);
}
}
MAKEFUNC(Put)
{
if (n_src>=2)
{
vars.Put(src[0],src[1]);
out.AddString(src[1]);
}
}
MAKEFUNC(PutQ)
{
if (n_src>=2)
{
vars.Put(src[0],src[1]);
}
}
MAKEFUNC(If)
{
if (n_src!=3) out.AddString(_TX("[INVALID $IF SYNTAX]"));
else
{
out.AddString(src[found_src[0] ? 1 : 2]);
}
}
MAKEFUNC(Iflonger)
{
if (n_src!=4) out.AddString(_TX("[INVALID $IFLONGER SYNTAX]"));
else
{
out.AddString(src[(int)t_strlen(src[0])>t_atoi(src[1]) ? 2 : 3]);
}
}
MAKEFUNC(Ifgreater)
{
if (n_src!=4) out.AddString(_TX("[INVALID $IFGREATER SYNTAX]"));
else
{
out.AddString(src[t_atoi(src[0])>t_atoi(src[1]) ? 2 : 3]);
}
}
MAKEFUNC(Upper)
{
if (n_src>=1)
{
T_CHAR * s=src[0];
while(*s)
{
out.AddChar(toupper(*(s++)));
}
}
}
MAKEFUNC(Lower)
{
if (n_src>=1)
{
T_CHAR * s=src[0];
while(*s)
{
out.AddChar(tolower(*(s++)));
}
}
}
MAKEFUNC(Pad)
{
if (n_src>=2)
{
T_CHAR *fill=_TX(" ");
if (n_src>=3 && src[2][0]) fill=src[2];
int num=t_atoi(src[1]);
T_CHAR *p=src[0];
while(*p) {out.AddChar(*(p++));num--;}
UINT fl=t_strlen(fill);
while(num>0) {out.AddChar(fill[(--num)%fl]);}
}
}
MAKEFUNC(Cut)
{
if (n_src>=2)
{
UINT num=t_atoi(src[1]);
T_CHAR *p=src[0];
while(*p && num) {out.AddChar(*(p++));num--;}
}
}
MAKEFUNC(PadCut)
{
if (n_src>=2)
{
T_CHAR *fill=_TX(" ");
if (n_src>=3 && src[2][0]) fill=src[3];
int num=t_atoi(src[1]);
T_CHAR *p=src[0];
while(*p && num>0) {out.AddChar(*(p++));num--;}
UINT fl=t_strlen(fill);
while(num>0) {out.AddChar(fill[(--num)%fl]);}
}
}
MAKEFUNC(Abbr)
{//abbr(string,len)
if (n_src==0 || (n_src>=2 && (int)t_strlen(src[0])<t_atoi(src[1]))) return;
T_CHAR * meta=src[0];
bool w=0,r=0;
while(*meta)
{
bool an=!separator(*meta) || *meta==']' || *meta=='[';
if (w && !an)
{
w=0;
}
else if (!w && an)
{
w=1;
if (!sepcmp(meta,_TX("a")) && !sepcmp(meta,_TX("the")))
{
r=need_full(meta)?1:0;
out.AddChar(*meta);
}
else r=0;
}
else if (w && r)
{
out.AddChar(*meta);
}
meta++;
}
}
MAKEFUNC(Caps)
{
if (n_src<1) return;
T_CHAR* sp=src[0];
int sep=1;
while(*sp)
{
T_CHAR c=*(sp++);
int s = separator(c);
if (!s && sep)
c=toupper(c);
else if (!sep) c=tolower(c);
sep=s;
out.AddChar(c);
}
}
MAKEFUNC(Caps2)
{
if (n_src<1) return;
T_CHAR* sp=src[0];
int sep=1;
while(*sp)
{
T_CHAR c=*(sp++);
int s = separator(c);
if (!s && sep)
c=toupper(c);
sep=s;
out.AddChar(c);
}
}
MAKEFUNC(Longest)
{
T_CHAR * ptr=0;
UINT n,m=0;
for(n=0;n<n_src;n++)
{
UINT l=t_strlen(src[n]);
if (l>m) {m=l;ptr=src[n];}
}
if (ptr) out.AddString(ptr);
}
MAKEFUNC(Shortest)
{
T_CHAR * ptr=0;
UINT n,m=(UINT)(-1);
for(n=0;n<n_src;n++)
{
UINT l=t_strlen(src[n]);
if (l<m) {m=l;ptr=src[n];}
}
if (ptr) out.AddString(ptr);
}
MAKEFUNC(Num)
{
if (n_src==2)
{
T_CHAR tmp[16];
T_CHAR tmp1[16];
sprintf(tmp1,_TX("%%0%uu"),t_atoi(src[1]));
sprintf(tmp,tmp1,t_atoi(src[0]));
out.AddString(tmp);
}
}
MAKEFUNC(Hex)
{
if (n_src==2)
{
T_CHAR tmp[16];
T_CHAR tmp1[16];
sprintf(tmp1,_TX("%%0%ux"),t_atoi(src[1]));
sprintf(tmp,tmp1,t_atoi(src[0]));
out.AddString(tmp);
}
}
MAKEFUNC(StrChr)
{
if (n_src==2)
{
T_CHAR * p=src[0];
T_CHAR s=src[1][0];
while(*p && *p!=s) p++;
if (*p==s) out.AddInt(1+p-src[0]);
else out.AddChar('0');
}
}
MAKEFUNC(StrRChr)
{
if (n_src==2)
{
T_CHAR * p=src[0],*p1=0;
T_CHAR s=src[1][0];
while(*p)
{
if (*p==s) p1=p;
p++;
}
if (p1) out.AddInt(1+p1-src[0]);
else out.AddChar('0');
}
}
MAKEFUNC(StrStr)
{
if (n_src==2)
{
T_CHAR * p=t_strstr(src[0],src[1]);
if (p) out.AddInt(1+p-src[0]);
else out.AddChar('0');
}
}
MAKEFUNC(SubStr)
{
int n1,n2;
if (n_src<2) return;
n1=t_atoi(src[1]);
if (n_src>=3)
{
n2=t_atoi(src[2]);
}
else n2=n1;
if (n1<1) n1=1;
if (n2>=n1)
{
n1--;
n2--;
while(n1<=n2 && src[0][n1])
{
out.AddChar(src[0][n1++]);
}
}
}
MAKEFUNC(Len)
{
if (n_src>=1) out.AddInt(t_strlen(src[0]));
}
MAKEFUNC(FileName)
{
if (n_src<1) return;
T_CHAR * p=src[0];
T_CHAR * p1=0;
while(*p)
{
if (*p=='\\' || *p=='/') p1=p;
p++;
}
if (p1) p1++;
else p1=p;
while(*p1 && *p1!='.') out.AddChar(*(p1++));
}
MAKEFUNC(Add)
{
UINT n;
int s=0;
for(n=0;n<n_src;n++)
{
s+=t_atoi(src[n]);
}
out.AddInt(s);
}
MAKEFUNC(Sub)
{
if (n_src>=1)
{
UINT n;
int s=t_atoi(src[0]);
for(n=1;n<n_src;n++)
{
s-=t_atoi(src[n]);
}
out.AddInt(s);
}
}
MAKEFUNC(Mul)
{
UINT n;
int s=1;
for(n=0;n<n_src;n++)
{
s*=t_atoi(src[n]);
}
out.AddInt(s);
}
MAKEFUNC(Div)
{
if (n_src>=1)
{
UINT n;
int s=t_atoi(src[0]);
for(n=1;n<n_src;n++)
{
int t=t_atoi(src[n]);
if (t) s/=t;
else t=0;
}
out.AddInt(s);
}
}
MAKEFUNC(Mod)
{
if (n_src>=1)
{
UINT n;
int s=t_atoi(src[0]);
for(n=1;n<n_src;n++)
{
int t=t_atoi(src[n]);
if (t) s%=t;
else t=0;
}
out.AddInt(s);
}
}
MAKEFUNC(Max)
{
if (!n_src) return;
int m=t_atoi(src[0]);
UINT n;
for(n=1;n<n_src;n++)
{
int t=t_atoi(src[n]);
if (t>m) m=t;
}
out.AddInt(m);
}
MAKEFUNC(Min)
{
if (!n_src) return;
int m=t_atoi(src[0]);
UINT n;
for(n=1;n<n_src;n++)
{
int t=t_atoi(src[n]);
if (t<m) m=t;
}
out.AddInt(m);
}
MAKEFUNC(Null)
{
}
struct
{
TEXTFUNC func;
const T_CHAR * name;
} FUNCS[]={
// Blah,"blah",
// Nop,"nop",
If,_TX("if"),
Upper,_TX("upper"),
Lower,_TX("lower"),
Pad,_TX("pad"),
Cut,_TX("cut"),
PadCut,_TX("padcut"),
Abbr,_TX("abbr"),
Caps,_TX("caps"),
Caps2,_TX("caps2"),
Longest,_TX("longest"),
Shortest,_TX("shortest"),
Iflonger,_TX("iflonger"),
Ifgreater,_TX("ifgreater"),
Num,_TX("num"),Num,_TX("dec"),
Hex,_TX("hex"),
StrChr,_TX("strchr"),
StrChr,_TX("strlchr"),
StrRChr,_TX("strrchr"),
StrStr,_TX("strstr"),
SubStr,_TX("substr"),
Len,_TX("len"),
Add,_TX("add"),
Sub,_TX("sub"),
Mul,_TX("mul"),
Div,_TX("div"),
Mod,_TX("mod"),
FileName,_TX("filename"),
Min,_TX("min"),
Max,_TX("max"),
Get,_TX("get"),
Put,_TX("put"),
PutQ,_TX("puts"),
Null,_TX("null"),
};
class FMT
{
private:
String str;
VarList *vars;
T_CHAR * spec;
TAGFUNC f;
TAGFREEFUNC ff;
void * fp;
T_CHAR * org_spec;
int found;
void Error(T_CHAR *e=0) {str.Reset();str.AddString(e ? e : _TX("[SYNTAX ERROR IN FORMATTING STRING]"));}
T_CHAR * _FMT(T_CHAR * s,UINT *f=0)
{
FMT fmt(this,s);
T_CHAR * c=(T_CHAR*)fmt;
if (f) *f=fmt.found;
found+=fmt.found;
return c;
}
static bool skipshit(T_CHAR** _p,T_CHAR *bl)
{
T_CHAR * p=*_p;
int bc1=0,bc2=0;
while(*p)
{
if (!bc1 && !bc2 && bl)
{
T_CHAR *z=bl;
while(*z)
{
if (*z==*p) break;
z++;
}
if (*z) break;
}
if (*p=='\'')
{
p++;
while(*p && *p!='\'') p++;
if (!*p) return 0;
}
else if (*p=='(') bc1++;
else if (*p==')')
{
if (--bc1<0) return 0;
}
else if (*p=='[') bc2++;
else if (*p==']')
{
if (--bc2<0) return 0;
}
p++;
}
*_p=p;
return *p && !bc1 && !bc2;
}
void run()
{
if (!spec) {Error();return;}
while(*spec)
{
if (*spec=='%')
{
spec++;
if (*spec=='%') {str.AddChar('%');spec++;continue;}
T_CHAR* s1=spec+1;
while(*s1 && *s1!='%') s1++;
if (!*s1) {Error();break;}
*s1=0;
T_CHAR * tag=f(spec,fp);
*s1='%';
//if (!tag) tag=tag_unknown;
if (tag && tag[0])
{
found++;
str.AddString(tag);
}
else
{
str.AddString(_TX("?"));
}
if (tag && ff) ff(tag,fp);
spec=s1+1;
}
else if (*spec=='$')
{
spec++;
if (*spec=='$') {str.AddChar('$');spec++;continue;}
T_CHAR * s1=spec+1;
while(*s1 && *s1!='(') s1++;
if (!*s1) {Error();break;}
T_CHAR * s2=s1+1;
if (!skipshit(&s2,_TX(")"))) {Error();break;}
if (!*s2) {Error();break;};
T_CHAR * p=s1+1;
T_CHAR* temp[64];
UINT temp_f[64];
UINT nt=0;
T_CHAR * p1=s1+1;
while(p<=s2 && nt<64)
{
if (!skipshit(&p,_TX(",)"))) {Error();return;}
if (p>s2 || (*p!=',' && *p!=')')) {Error(_TX("internal error"));return;}
T_CHAR bk=*p;
*p=0;
temp[nt]=_FMT(p1,&temp_f[nt]);
nt++;
*p=bk;;
p1=p+1;
p++;
}
*s1=0;
UINT n;
TEXTFUNC fn=0;
for(n=0;n<TABSIZE(FUNCS);n++)
{
if (!t_stricmp(spec,FUNCS[n].name)) {fn=FUNCS[n].func;break;}
}
*s1='(';
if (fn)
{
fn(nt,temp,temp_f,str,*vars);
}
else
{
str.AddString(_TX("[UNKNOWN FUNCTION]"));
}
for(n=0;n<nt;n++) free(temp[n]);
spec=s2+1;
}
else if (*spec=='\'')
{
spec++;
if (*spec=='\'') {str.AddChar('\'');spec++;continue;}
T_CHAR * s1=spec+1;
while(*s1 && *s1!='\'') s1++;
if (!*s1) {Error();break;}
*s1=0;
str.AddString(spec);
*s1='\'';
spec=s1+1;
}
else if (*spec=='[')
{
spec++;
T_CHAR * s1=spec;
if (!skipshit(&s1,_TX("]"))) {Error();break;}
T_CHAR bk=*s1;
*s1=0;
FMT fmt(this,spec);
fmt.run();
if (fmt.found)
{
str.AddString(fmt);
found+=fmt.found;
}
*s1=bk;
spec=s1+1;
}
else if (*spec==']' || *spec=='(' || *spec==')') {Error();break;}
else
{
str.AddChar(*spec);
spec++;
}
}
}
FMT(FMT* base,T_CHAR * _spec)
{
vars=base->vars;
found=0;
org_spec=0;
f=base->f;
ff=base->ff;
fp=base->fp;
spec=_spec;
}
public:
FMT(T_CHAR * p_spec,TAGFUNC _f,TAGFREEFUNC _ff,void * _fp,VarList * _vars)
{
vars=_vars;
found=0;
org_spec=spec=t_strdup(p_spec);
f=_f;
ff=_ff;
fp=_fp;
}
operator T_CHAR*()
{
run();
return str.GetBuf();
}
~FMT()
{
if (org_spec) free(org_spec);
}
};
extern "C"
{
UINT tagz_format(T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void *fp,T_CHAR* out,UINT max)
{
T_CHAR * zz=tagz_format_r(spec,f,ff,fp);
UINT r=0;
while(r<max-1 && zz[r])
{
out[r]=zz[r];
r++;
}
out[r]=0;
free(zz);
return r;
}
T_CHAR * tagz_format_r(T_CHAR* spec,TAGFUNC f,TAGFREEFUNC ff,void * fp)
{
VarList vars;
return FMT(spec,f,ff,fp,&vars);
}
//char tagz_manual[]="TODO: WTFM";
char tagz_manual[]="Syntax reference: \n"
"\n"
"* %tagname% - inserts field named <tagname>, eg. \"%artist%\"\n"
"* $abbr(x) - inserts abbreviation of x, eg. \"$abbr(%album%)\" - will convert album name of \"Final Fantasy VI\" to \"FFVI\"\n"
"* $abbr(x,y) - inserts abbreviation of x if x is longer than y characters; otherwise inserts full value of x, eg. \"$abbr(%album%,10)\"\n"
"* $lower(x), $upper(x) - converts x to in lower/uppercase, eg. \"$upper(%title%)\"\n"
"* $num(x,y) - displays x number and pads with zeros up to y characters (useful for track numbers), eg. $num(%tracknumber%,2)\n"
"* $caps(x) - converts first letter in every word of x to uppercase, and all other letters to lowercase, eg. \"blah BLAH\" -> \"Blah Blah\"\n"
"* $caps2(x) - similar to $caps, but leaves uppercase letters as they are, eg. \"blah BLAH\" -> \"Blah BLAH\"\n"
"* $if(A,B,C) - if A contains at least one valid tag, displays B, otherwise displays C; eg. \"$if(%artist%,%artist%,unknown artist)\" will display artist name if present; otherwise will display \"unknown artist\"; note that \"$if(A,A,)\" is equivalent to \"[A]\" (see below)\n"
"* $longest(A,B,C,....) - compares lengths of output strings produced by A,B,C... and displays the longest one, eg. \"$longest(%title%,%comment%)\" will display either title if it's longer than comment; otherwise it will display comment\n"
"* $pad(x,y) - pads x with spaces up to y characters\n"
"* $cut(x,y) - truncates x to y characters\n"
"* $padcut(x,y) - pads x to y characters and truncates to y if longer\n"
"* [ .... ] - displays contents of brackets only if at least one of fields referenced inside has been found, eg. \"%artist% - [%album% / ]%title%\" will hide [] block if album field is not present\n"
"* \' (single quotation mark) - outputs raw text without parsing, eg, \'blah$blah%blah[][]\' will output the contained string and ignore all reserved characters (%,$,[,]) in it; you can use this feature to insert square brackets for an example.\n"
"\n"
"eg. \"[%artist% - ][$abbr(%album%,10)[ %tracknumber%] / ]%title%[ %streamtitle%]\"\n";
}
+26
View File
@@ -0,0 +1,26 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UINT
typedef unsigned int UINT;
#endif
#ifdef TAGZ_UNICODE
typedef unsigned short T_CHAR;
#else
#define T_CHAR char
#endif
typedef T_CHAR* (*TAGFUNC)(T_CHAR * tag,void * p); //return 0 if not found
typedef void (*TAGFREEFUNC)(T_CHAR * tag,void * p);
UINT tagz_format(T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void *fp,T_CHAR * out,UINT max);
T_CHAR * tagz_format_r(T_CHAR * spec,TAGFUNC f,TAGFREEFUNC ff,void * fp);
extern char tagz_manual[];
#ifdef __cplusplus
}
#endif
+62
View File
@@ -0,0 +1,62 @@
#include "main.h"
TITLELISTTYPE TitleListTerminator;
TITLELISTTYPE *TitleLinkedList = &TitleListTerminator;
void initTitleList(void)
{
TitleListTerminator.Next = NULL;
TitleListTerminator.timer = 0;
}
/* -----------------------------------------------------------------------------------------------
Adds an entry in the list
-----------------------------------------------------------------------------------------------*/
TITLELISTTYPE *newTitleListEntry(void)
{
TITLELISTTYPE *TitleObject = (TITLELISTTYPE *)calloc(1,sizeof(TITLELISTTYPE)); /* Allocate new entry */
TitleObject->Next = (void *)TitleLinkedList; /* New entry's next is old list _head */
TitleLinkedList = TitleObject; /* new _head is new entry */
return TitleObject; /* return pointer to new entry */
}
/* -----------------------------------------------------------------------------------------------
Removes an entry from the list
-----------------------------------------------------------------------------------------------*/
void removeTitleListEntry(TITLELISTTYPE *Entry)
{
TITLELISTTYPE *TitleObject = TitleLinkedList;
if (TitleObject == &TitleListTerminator) return; /* List is empty */
if (TitleObject == (void *)Entry)
{
TitleLinkedList = (TITLELISTTYPE *)TitleObject->Next;
free(TitleObject);
}
else
while (TitleObject->Next) /* While not terminator */
{
if ((TITLELISTTYPE *)(TitleObject->Next) == (void *)Entry) /* If next entry is what we're looking for */
{
TitleObject->Next = ((TITLELISTTYPE *)(TitleObject->Next))->Next; /* Skip one entry */
free(Entry); /* free the entry we dont' want anymore */
}
TitleObject = (TITLELISTTYPE *)TitleObject->Next; /* Get next entry */
}
}
void clearTitleList()
{
TITLELISTTYPE *TitleObject = TitleLinkedList;
if (TitleObject == &TitleListTerminator) return; /* List is empty */
while (TitleObject->Next) /* While not terminator */
{
TITLELISTTYPE *KillMe=TitleObject;
TitleObject = (TITLELISTTYPE *)KillMe->Next; /* Get next entry */
free(KillMe);
}
TitleLinkedList = &TitleListTerminator;
}
+97
View File
@@ -0,0 +1,97 @@
Changes:
* [a7] made seeking work (slightly) better on realshitbox encoded mp3s (with broken
VBR headers)
* [a7] made save http file location persistent when turned off
* [a7] fixed id3v2 bug (1 character strings not being displayed correctly)
* [a6] fixed stupid file association bug (oops)
* [a5] fixed crash when repeating a non-existing file bug (added a Sleep())
* [a5] fixed shoutcast disk writer issue
* [a5] fixed SendMessage() potential issues (using postmessage and SendMessageTimeout() now)
* [a5] added new format-for-non-id3 files, added 'use id3 tag' option, which lets you disable them
completely
* [a5] return of the file association list
* [a5] made temp file handling slightly better-- checks for read only, better error messages.
* [a4] fixed lots of potential (and a few serious) bugs in id3lib.
* [a4] fixed pause right after playback starts bug
* fixed crash/hang/freeze when reading some mp3 files with a weird id3v2 tag (as found in some
real jukebox generated mp3s, etc...)
* this one will break a few things (i.e. windowshade vis), because justin is updating it to go
with winamp 2.7
* all code is now win32 file io
* %a will now display id3v1.1/v2 track #
* fixed id3v1 reading bug that added year field in album field
* why does it ask me to stop the currently playing file when updating an id3v2 tag ?
answer:
whenever you strip or update an id3v2 tag, it creates a tmp file (FILENAME.new),
writes it out, and if it wrote it out correctly, then it renames the original
to FILENAME.bak, and renames the new one to FILENAME, and if that was successful,
then deletes FILENAME.bak). this is required because of the implementation of the
id3v2 protocol.
* [2.666b] fixed crash when using crossfading output plugin
* [2.666b] fixed the issue that files with large id3v2 tags don't seek correctly
* [2.666b] added id3v1.1 track field editing
* [2.666b] simplified id3 edit box (removed all save/remove buttons, all is done via
update button now)
* [2.666b] fixed some more stuff in id3 edit box... should be more reliable
* [2.666b] contains devil easter egg
* winamp 2.666 release
* [a18] dll is smaller
* [a18] fixed vbr header reading on some musicmatch/crap generated files
* [a18] id3v1.1 track # reading support (who cares about id3v1.1 writing?)
* [a18] crc checking is now activable in prefs box
* [a18] "show average on VBR files" is now activable in prefs box
* [a17] "update tags" button only saves selected tags now
* [a17] vbr-division-by-0-bug-on-edit fixed
* [a17] long id3v1 tags reading corrected
* [a17] id3v2 url tag will now interact with the minibrowser
* [a17] added id3v2 variables to id3 title formatting
* [a16] corrected crash/bug in id3v2 genre reading
* [a16] corrected id3v2 comment editor to support multiple lines :)
* [a16] new "stop track" button in id3v2 editor so you don't have to retype everything
when id3v2 can't be updated because file is locked
* [a16] added track number id3v2 field
* [a16] id3v2 warnings no more appear under id3 tag editor
* [a10] streaming info improvements/fixes
* [a10] made more options for streaming title formatting (for you brennan)
* [a10] still needs better id3v2 reading writing. THIS IS ON THE WAY, CHILL.
* [a9] improved streaming error notification (i.e. on can't connect, can't resolve, timeout)
* [a9] made streaming detect id3v2 tag and skip it (todo: make it look at the id3v2 tag and use it)
* [a9] updated id3v2 support to detect invalid id3v2 tags, and autodetect their actual
size
* [a9] info box now tells you where the first mpeg header was found (useful)
* [a8] fixed live365 streaming (they need a space between User-Agent:
and the agent string. those assclowns.)
* [a8] rescheduled some of the polyphase for a few cycles
* [a7] bugfix: vbr headers read when id3v2 tag is present now
* [a7] downsampling modes have better vis support
* [a7] id3v2 writing support
* [a7] stream info box
* [a6] mmm.
* [a6] return of working id3 code
* [a5] optimized bitgetting.
* [a5] keen streaming buffer indicators in mini-vis display
* [a5] made fast eq modes optional (can use slow pcm eq like wav files)
* [a5] fixed fastly-changing-tracks bug
* [a4] tuned decode loop more
* [a4] optimized huffman decoding
* [a3] improved network code. updates status in title area.
* [a3] layer 1/2 eq code
* [a3] optimized decoder some more. we can still make it a bit faster me thinks.
* [a3] moved more code into decode thread.. should act much more asynchronously
* [a2] Improved skip robustness
* [a2] Optimized decoder for ppro. changed 8 bit mode for speed.
* [a2] partial ID3V2 support
* Fully ISO compliant decoder (based on FHG's implementation)
* Also fully supports MPEG 2.5 low bitrates.
* Full MPEG Layer 1 and Layer 2 support
* Improved equalizer code
* Optimized visualization data generation code
* Improved network code (single threaded)
* Lots of other cleanups
todo:
make more blip resistant (see pvd.mp3)
remove seek-blip
+79
View File
@@ -0,0 +1,79 @@
#include "uvox_3901.h"
#include "api__in_mp3.h"
#include "api/service/waservicefactory.h"
#include <strsafe.h>
#include "in2.h"
extern In_Module mod;
#include "FactoryHelper.h"
Ultravox3901::Ultravox3901() : parser(0)
{
title[0]=album[0]=artist[0]=album_art_url[0]=0;
ServiceBuild(parser, obj_xmlGUID);
if (parser)
{
parser->xmlreader_registerCallback(L"metadata\fsong\f*", this);
parser->xmlreader_open();
}
}
Ultravox3901::~Ultravox3901()
{
ServiceRelease(parser, obj_xmlGUID);
}
int Ultravox3901::Parse(const char *xml_data)
{
if (parser)
{
int ret = parser->xmlreader_feed((void *)xml_data, strlen(xml_data));
if (ret != API_XML_SUCCESS)
return ret;
return parser->xmlreader_feed(0, 0);
}
return API_XML_FAILURE;
}
void Ultravox3901::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
{
if (!_wcsicmp(xmltag, L"name"))
{
StringCbCatW(title, sizeof(title), str);
}
else if (!_wcsicmp(xmltag, L"album"))
{
StringCbCatW(album, sizeof(album), str);
}
else if (!_wcsicmp(xmltag, L"artist"))
{
StringCbCatW(artist, sizeof(artist), str);
}
else if (!_wcsicmp(xmltag, L"album_art"))
{
StringCbCatW(album_art_url, sizeof(album_art_url), str);
}
}
int Ultravox3901::GetExtendedData(const char *tag, wchar_t *data, int dataLen)
{
if (!_stricmp(tag, "uvox/title"))
StringCchCopy(data, dataLen, title);
else if (!_stricmp(tag, "uvox/album"))
StringCchCopy(data, dataLen, album);
else if (!_stricmp(tag, "uvox/artist"))
StringCchCopy(data, dataLen, artist);
else if (!_stricmp(tag, "uvox/albumart"))
StringCchCopy(data, dataLen, album_art_url);
else
return 0;
return 1;
}
#define CBCLASS Ultravox3901
START_DISPATCH;
VCB(ONCHARDATA, TextHandler)
END_DISPATCH;
#undef CBCLASS
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include "../xml/obj_xml.h"
#include "../xml/ifc_xmlreadercallback.h"
class Ultravox3901 : public ifc_xmlreadercallback
{
public:
Ultravox3901();
~Ultravox3901();
int Parse(const char *xml_data);
int GetExtendedData(const char *tag, wchar_t *data, int dataLen);
private:
/* XML callbacks */
void TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
obj_xml *parser;
wchar_t title[256],artist[256],album[256],album_art_url[4096];
RECVS_DISPATCH;
};
+77
View File
@@ -0,0 +1,77 @@
#include "uvox_3902.h"
#include "api__in_mp3.h"
#include "api/service/waservicefactory.h"
#include <strsafe.h>
#include "in2.h"
extern In_Module mod;
#include "FactoryHelper.h"
Ultravox3902::Ultravox3902() : parser(0)
{
title[0]=album[0]=artist[0]=0;
ServiceBuild(parser, obj_xmlGUID);
if (parser)
{
parser->xmlreader_setCaseSensitive();
parser->xmlreader_registerCallback(L"metadata\f*", this);
parser->xmlreader_open();
}
}
Ultravox3902::~Ultravox3902()
{
if (parser)
{
parser->xmlreader_unregisterCallback(this);
parser->xmlreader_close();
}
ServiceRelease(parser, obj_xmlGUID);
}
int Ultravox3902::Parse(const char *xml_data)
{
if (parser)
{
int ret = parser->xmlreader_feed((void *)xml_data, strlen(xml_data));
if (ret != API_XML_SUCCESS)
return ret;
return parser->xmlreader_feed(0, 0);
}
return API_XML_FAILURE;
}
void Ultravox3902::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
{
if (!_wcsicmp(xmlpath, L"metadata\fTIT2"))
{
StringCbCatW(title, sizeof(title), str);
}
else if (!_wcsicmp(xmlpath, L"metadata\fTALB"))
{
StringCbCatW(album, sizeof(album), str);
}
else if (!_wcsicmp(xmlpath, L"metadata\fTPE1"))
{
StringCbCatW(artist, sizeof(artist), str);
}
}
int Ultravox3902::GetExtendedData(const char *tag, wchar_t *data, int dataLen)
{
if (!_stricmp(tag, "title"))
StringCchCopy(data, dataLen, title);
else if (!_stricmp(tag, "album"))
StringCchCopy(data, dataLen, album);
else if (!_stricmp(tag, "artist"))
StringCchCopy(data, dataLen, artist);
else
return 0;
return 1;
}
#define CBCLASS Ultravox3902
START_DISPATCH;
VCB(ONCHARDATA, TextHandler)
END_DISPATCH;
#undef CBCLASS
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include "../xml/obj_xml.h"
#include "../xml/ifc_xmlreadercallback.h"
class Ultravox3902 : public ifc_xmlreadercallback
{
public:
Ultravox3902();
~Ultravox3902();
int Parse(const char *xml_data);
int GetExtendedData(const char *tag, wchar_t *data, int dataLen);
private:
/* XML callbacks */
void TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
obj_xml *parser;
wchar_t title[256],artist[256],album[256];
RECVS_DISPATCH;
};
+39
View File
@@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#include "../../../Winamp/buildType.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,6,0,0
PRODUCTVERSION WINAMP_PRODUCTVER
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Winamp SA"
VALUE "FileDescription", "Winamp Input Plug-in"
VALUE "FileVersion", "4,6,0,0"
VALUE "InternalName", "Nullsoft MPEG Audio Decoder"
VALUE "LegalCopyright", "Copyright © 1998-2023 Winamp SA"
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
VALUE "OriginalFilename", "in_mp3.dll"
VALUE "ProductName", "Winamp"
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END