|
論壇說明 |
歡迎您來到『史萊姆論壇』 ^___^ 您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的! 請點擊這裡:『註冊成為我們的一份子!』 |
|
主題工具 | 顯示模式 |
2004-03-29, 05:11 AM | #1 |
榮譽會員
|
可以直接將APE轉為MP3的LAME
在BBS論壇中找到的幾種方法似乎都不是很方便(也許我沒有找到),無意中發現有個高手在Lame.exe的基礎上直接做了修改,使其支持APE和CUE格式。
我想還是有很多人像我一樣沒有太多的空間來存放APE的,所以把這個好東東推薦給大家。 附件zip檔案中有一個MACDLL.DLL是從Monkey's Audio中拿來的,修改過的LAME.EXE在轉APE檔案時需要用到的,把它和LAME.EXE放在一個目錄下就可以了。 我是這麼來把硬碟上的所有的APE檔案都轉成MP3的: 1、先找到所有的APE檔案(譬如用Total Commander),找到以後把所有的檔案的全部路徑複製到剪貼板並放到一個文本檔案中,譬如ape.lst檔案,這樣其中每一行就是一個完整的ape檔案的路徑; 2、寫一個簡單的批次處理,譬如ape2mp3.bat: @echo off title ape2mp3 for /f "delims=" %%a in (ape.lst) do ( if exist "%%a" ( start /LOW /B /WAIT lame --apeinput --preset extreme "%%a" "%%a.mp3" if errorlevel 1 ( @echo Error encoding "%%a" to "%%a.mp3" >> ape2mp3.log ) else ( @echo Encoded "%%a" to "%%a.mp3". >> ape2mp3.log del "%%a" if errorlevel 1 ( @echo Cannot delete "%%a" after encoding is completed. >> ape2mp3.log ) ) ) ) 3、把ape2mp3.bat和ape.lst放在LAME.EXE的所在目錄下,然後執行ape2mp3.bat即可。 !!注意:這個批次處理會在成功轉完一個ape檔案時刪除它!! 帖子出發點是好的。但是實際根本不用這麼麻煩,只需要用foobar+lame就行了。簡單得很。 而且可以通過cue檔案來寫入idv1標籤。 lame 3.93系列是最不推薦用的啊,真的很lame. 要用lame還是用比較穩定的3.90.3或3.90.2吧 3.94alpha在測試階段,不錯,但有時會破功。 f -ruN lame-3.90.2/Makefile.MSVC lame-3.90.2_cuesheet-0.5.2_ape/Makefile.MSVC --- lame-3.90.2/Makefile.MSVC Sun Nov 4 15:42:16 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/Makefile.MSVC Fri Apr 4 02:11:16 2003 @@ -286,7 +286,8 @@ BRHIST_SWITCH = /DBRHIST TIMER_SWITCH = -CPP_OPTS = /DHAVE_CONFIG_H -I. +CPP_OPTS = /DHAVE_CONFIG_H /DHAVE_NYAOCHI_MODIFICATION +CPP_OPTS = $(CPP_OPTS) /DHAVE_CUESHEET /DHAVE_MONKEYS -I. @@ -365,13 +366,17 @@ LN_SWITCHES = $(LN_OPTS) lame_sources = \ - frontend/main.c + frontend/main.c \ + frontend/cuesheet.c mpx_sources = \ frontend/gpkplotting.c \ frontend/gtkanal.c \ frontend/mp3x.c +mnkylib_sources = \ + frontend/get_audio_monkeys.cpp + dll_sources = \ dll/BladeMP3EncDll.c @@ -422,10 +427,14 @@ LAME_OBJ = $(lame_sources:.c=.obj) MPX_OBJ = $(mpx_sources:.c=.obj) DLL_OBJ = $(dll_sources:.c=.obj) +MNKY_OBJ = $(mnkylib_sources:.cpp=.obj) .c.obj: @$(CC) $(CPP_OPTS) $(CC_SWITCHES) -Iinclude -Ilibmp3lame -Impglib \ $(CC_OUT)$@ -c $< +.cpp.obj: + @$(CC) $(CPP_OPTS) $(CC_SWITCHES) -Iinclude -Ilibmp3lame -Impglib \ + $(CC_OUT)$@ -c $< #__ NASM ______________________________________________________________________ # @@ -482,6 +491,11 @@ @echo --- COMMON FRONTEND STUFF UPTODATE --- @echo. +monkey: $(MNKY_OBJ) + @echo. + @echo --- MONKEY'S AUDIO STUFF UPTODATE --- + @echo. + libA: $(LIB_OBJ) @echo. @echo --- LAME MP3 ENCODING LIBRARY UPTODATE --- @@ -494,9 +508,9 @@ lib: $(ASM_OBJ) libA libB -$(T_LAME) : config.h lib common $(LAME_OBJ) +$(T_LAME) : config.h lib common monkey $(LAME_OBJ) @$(LN) $(LN_OUT)$@ $(LN_SWITCHES) $(LIBSNDFILE) $(VORBISLIB) \ - $(ASM_OBJ) $(LIB_OBJ) $(MPG_OBJ) $(CMMN_OBJ) $(LAME_OBJ) + $(ASM_OBJ) $(LIB_OBJ) $(MPG_OBJ) $(CMMN_OBJ) $(LAME_OBJ) $(MNKY_OBJ) @echo. @echo --=* $@ ready *=-- @echo. Binary files lame-3.90.2/dshow/Thumbs.db and lame-3.90.2_cuesheet-0.5.2_ape/dshow/Thumbs.db differ diff -ruN lame-3.90.2/frontend/cuesheet.c lame-3.90.2_cuesheet-0.5.2_ape/frontend/cuesheet.c --- lame-3.90.2/frontend/cuesheet.c Thu Jan 1 09:00:00 1970 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/cuesheet.c Fri Apr 4 02:11:16 2003 @@ -0,0 +1,345 @@ +/* + * cuesheet.c + * Copyright(c) 2001-2003 by Nyaochi. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <string.h> +#include "cuesheet.h" + +#define MAX_LINE 4096 +#ifndef _MAX_PATH +#define _MAX_PATH 4096 +#endif + +static const char *getToken(const char *pSrc, char *pDst); +static char *letString(char **p, const char *szString); +static unsigned long getPackedTime(const char *szTime); + +cuesheet *cuesheet_open(const char *szFileName, int bSameFolder) +{ + cuesheet *pCueSheet = NULL; /* cuesheet structure */ + int nCueSheet = 0; /* number of trakcs */ + char szFile[_MAX_PATH]; /* filename */ + FILE *fp; /* file pointer for cuesheet. */ + + /* Initialize for pCueSheet, nCueSheet. */ + pCueSheet = (cuesheet *)malloc(sizeof(cuesheet)); + if (pCueSheet == NULL) { + goto exit_fail; + } + memset(pCueSheet, 0, sizeof(cuesheet)); + nCueSheet = 1; + + /* Open cuesheet file. */ + fp = fopen(szFileName, "r"); + if (fp == NULL) { + /* Failed to open cuesheet. */ + goto exit_fail; + } else { + /* Parse cuesheet. */ + int nTrack = 0; /* */ + int nMaxIndex = 0; + char szLine[MAX_LINE]; + char szParam1[MAX_LINE]; + char szParam2[MAX_LINE]; + char szParam3[MAX_LINE]; + + while (fgets(szLine, MAX_LINE, fp) != NULL) { + const char *p = szLine; + + /* get szParam1, szParam2*/ + p = getToken(p, szParam1); + p = getToken(p, szParam2); + + if (strcmp(szParam1, "TRACK") == 0) { + p = getToken(p, szParam3); + if (strcmp(szParam3, "AUDIO") == 0) { + nTrack++; + if (nCueSheet <= nTrack) { + /* expand the cuesheet array */ + cuesheet *pNewCueSheet = realloc(pCueSheet, sizeof(cuesheet) * nCueSheet * 2); + if (pNewCueSheet == NULL) { + goto exit_fail; + } + memset(pNewCueSheet + nCueSheet, 0, sizeof(cuesheet) * nCueSheet); + nCueSheet *= 2; + pCueSheet = pNewCueSheet; + } + pCueSheet[nTrack].nTrack = atoi(szParam2); + letString(&pCueSheet[nTrack].szFileName, szFile); + } + } else if (strcmp(szParam1, "TITLE") == 0) { + letString(&pCueSheet[nTrack].szTitle, szParam2); + } else if (strcmp(szParam1, "PERFORMER") == 0) { + letString(&pCueSheet[nTrack].szPerformer, szParam2); + } else if (strcmp(szParam1, "FILE") == 0) { + if (bSameFolder) { + char *p, *p1, *p2; + p1 = strrchr(szFileName, '\\'); + p2 = strrchr(szFileName, '/'); + p = p1 < p2 ? p2 : p1; + memset(szFile, '\0', sizeof(szFile)); + if (p != NULL) { + strncpy(szFile, szFileName, (int)(p - szFileName + 1)); + } + p1 = strrchr(szParam2, '\\'); + p2 = strrchr(szParam2, '/'); + p = p1 < p2 ? p2 : p1; + if (p != NULL) { + strcat(szFile, p + 1); + } else { + strcat(szFile, szParam2); + } + } else { + strcpy(szFile, szParam2); + } + } else if (strcmp(szParam1, "INDEX") == 0) { + int index = atoi(szParam2); + p = getToken(p, szParam3); + + if (pCueSheet[nTrack].lpIndex == NULL) { + nMaxIndex = 2; + pCueSheet[nTrack].lpIndex = (unsigned long *)malloc(sizeof(unsigned long) * nMaxIndex); + if (pCueSheet[nTrack].lpIndex == NULL) { + goto exit_fail; + } + memset(pCueSheet[nTrack].lpIndex, 0xFF, sizeof(unsigned long) * nMaxIndex); + } + if (index >=nMaxIndex) { + unsigned long *pNewIndex = realloc(pCueSheet[nTrack].lpIndex, sizeof(unsigned long) * index * 2); + if (pNewIndex == NULL) { + goto exit_fail; + } + memset(pNewIndex + nMaxIndex, 0xFF, sizeof(unsigned long) * (index * 2 - index)); + } + pCueSheet[nTrack].lpIndex[index] = getPackedTime(szParam3); + if (pCueSheet[nTrack].nIndex < index + 1) { + pCueSheet[nTrack].nIndex = index + 1; + } + } + } + pCueSheet[0].nTrack = nTrack; + fclose(fp); + } + return pCueSheet; + + exit_fail: + free(pCueSheet); + return NULL; +} + +void cuesheet_close(cuesheet *p) +{ + int i, nTracks; + + if (p == NULL) { + return; + } + + nTracks = p[0].nTrack; + for (i = 0;i <= nTracks;i++) { + /* free all the array. */ + free(p[i].szFileName); + free(p[i].szPerformer); + free(p[i].szTitle); + free(p[i].lpIndex); + } + free(p); +} + +int cuesheet_getNumberOfTracks(const cuesheet *pCueSheet) +{ + if (!pCueSheet) { + return 0xFFFFFFFF; + } + return pCueSheet[0].nTrack; +} + +const char *cuesheet_getTitle(const cuesheet *pCueSheet, int track) +{ + if (!pCueSheet) { + return NULL; + } + if (track < 0 || pCueSheet[0].nTrack < track) { + return NULL; + } + return pCueSheet[track].szTitle; +} +const char *cuesheet_getPerformer(const cuesheet *pCueSheet, int track) +{ + if (!pCueSheet) { + return NULL; + } + if (track < 0 || pCueSheet[0].nTrack < track) { + return NULL; + } + return pCueSheet[track].szPerformer; +} + +const char *cuesheet_getFilename(const cuesheet *pCueSheet, int track) +{ + if (!pCueSheet) { + return NULL; + } + if (track < 1 || pCueSheet[0].nTrack < track) { + return NULL; + } + return pCueSheet[track].szFileName; +} + +unsigned long cuesheet_getBeginOfTrack(const cuesheet *pCueSheet, int track) +{ + if (!pCueSheet) { + return 0xFFFFFFFF; + } + if (track < 1 || pCueSheet[0].nTrack < track) { + return 0xFFFFFFFF; + } + if (pCueSheet[track].nIndex < 2) { + return 0xFFFFFFFF; + } + return pCueSheet[track].lpIndex[1]; +} + +unsigned long cuesheet_getEndOfTrack(const cuesheet *pCueSheet, int track, int bNoGap) +{ + /* check if null pointer */ + if (!pCueSheet) { + return CS_PT_INVALID; + } + + /* check if track in proper range */ + if (track < 1 || pCueSheet[0].nTrack < track) { + return CS_PT_INVALID; + } + + if (track == pCueSheet[0].nTrack) { + /* track is the last track */ + return 0xFF000000; + } else { + /* track isn't the last track */ + if (strcmp(pCueSheet[track].szFileName, pCueSheet[track+1].szFileName) != 0) { + return 0xFF000000; + } else { + if (pCueSheet[track+1].nIndex < 2) { + return 0xFFFFFFFF; + } + if (bNoGap) { + if (pCueSheet[track + 1].lpIndex[0] != CS_PT_INVALID) + return pCueSheet[track + 1].lpIndex[0]; + else + return pCueSheet[track + 1].lpIndex[1]; + } else { + return pCueSheet[track + 1].lpIndex[1]; + } + } + } +} + +static char *letString(char **p, const char *szString) +{ + if ((*p) != NULL) { + free(*p); + } + + (*p) = (char *)malloc(strlen(szString) + 1); + strcpy((*p), szString); + return (*p); +} + +static const char *getToken(const char *pSrc, char *pDst) +{ + const char *p = pSrc; + char *q = pDst; + int bQuote = 0; + + // init. + *q = '\0'; + + while(*p != '\0' && *p != '\n' && *p != '\r') { + switch (*p) { + case ' ': + if (q != pDst) { + if (bQuote) { + *q++ = *p; + } else { + goto exit_success; + } + } + break; + case '"': + bQuote = !bQuote; + break; + case '\\': + if (*(p + 1) == '"') { + *q++ = *++p; + } else { + *q++ = *p; + } + break; + default: + *q++ = *p; + break; + } + p++; + } + + exit_success: + *q = '\0'; + return p; +} + +static unsigned long getPackedTime(const char *szTime) +{ + unsigned long ulPackedTime = 0; + const char *p = szTime; + char *q; + + do { + if (szTime == NULL) { + break; + } + if (strlen(szTime) < 8) { + break; + } + ulPackedTime += strtoul(p, &q, 10) << 16; + if (*q != ':') { + break; + } + p = q; + ulPackedTime += strtoul(p+1, &q, 10) << 8; + if (*q != ':') { + break; + } + p = q; + ulPackedTime += strtoul(p+1, &q, 10); + return ulPackedTime; + } while (0); + + return 0xFFFFFFFF; +} + +unsigned long cuesheet_pt2SampleNum(unsigned long ulPackedTime, unsigned long ulSamplingFrequency) +{ + unsigned char min, sec, frame; + min = (unsigned char)((ulPackedTime & 0x00FF0000) >> 16); + sec = (unsigned char)((ulPackedTime & 0x0000FF00) >> 8); + frame = (unsigned char)(ulPackedTime & 0x000000FF); + + return (ulSamplingFrequency * (min * 60 + sec) + ulSamplingFrequency / 75 * frame); +} + +void cuesheet_pt2String(unsigned long ulPackedTime, char *szTime) +{ + sprintf( + szTime, + "%02d:%02d:%02d", + (ulPackedTime & 0x00FF0000) >> 16, + (ulPackedTime & 0x0000FF00) >> 8, + (ulPackedTime & 0x000000FF) + ); +} + diff -ruN lame-3.90.2/frontend/cuesheet.h lame-3.90.2_cuesheet-0.5.2_ape/frontend/cuesheet.h --- lame-3.90.2/frontend/cuesheet.h Thu Jan 1 09:00:00 1970 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/cuesheet.h Fri Apr 4 02:11:16 2003 @@ -0,0 +1,124 @@ +/* + * cuesheet.h - Cuesheet Parser. + * Copyright(c) 2001-2003 by nyaochi. + */ +#ifndef _CHESHEET_H_ +#define _CUESHEET_H_ + +/** + * Constant Definition. + */ +enum { + /** Packed Time expression for the end of image */ + CS_PT_END = 0xFF000000, + /** Packed Time expression for invalid time */ + CS_PT_INVALID = 0xFFFFFFFF +}; + +/** + * Structure that stands for each track. + * This structure array is supporsed to be created by + * cuesheet_open() function and freed by cuesheet_close() function. + */ +struct tagCueSheet { + /** Filename of WAVE */ + char *szFileName; + /** Track Number */ + int nTrack; + /** Title */ + char *szTitle; + /** Performer */ + char *szPerformer; + /** Number of Indexes */ + int nIndex; + /** Array of indexes */ + unsigned long *lpIndex; +}; +typedef struct tagCueSheet cuesheet; + + +/***************************************************************** + * Prototype Definition + *****************************************************************/ + +/****** Create and Destroy function ******/ +/** + * Open and parse cuesheet. + * @param szCueSheet filename of cuesheet. + * @param bSameFolder if true, the directory of wave file is same as cuesheet. + * @return + */ +cuesheet *cuesheet_open(const char *szFileName, int bSameFolder); + +/** + * Close cuesheet. + * @param pCueSheet Pointer to the cuesheet structure array + */ +void cuesheet_close(cuesheet *pCueSheet); + +/****** Access function ******/ +/** + * Get number of trakcs. + * @param pCueSheet Pointer to the cuesheet structure array + * @return Number of tracks + */ +int cuesheet_getNumberOfTracks(const cuesheet *pCueSheet); +/** + * Get title of a specified track. + * @param pCueSheet Pointer to the cuesheet structure array + * @param track Track nunber + * @return Pointer to the string of title + */ +const char *cuesheet_getTitle(const cuesheet *pCueSheet, int track); +/** + * Get perfomer infomation of a specified track. + * @param pCueSheet Pointer to the cuesheet structure array + * @param track Track nunber + * @return Pointer to the string of performer infomation + */ +const char *cuesheet_getPerformer(const cuesheet *pCueSheet, int track); +/** + * Get filename of a specified track. + * @param pCueSheet Pointer to the cuesheet structure array + * @param track Track nunber + * @return Pointer to the string of filename + */ +const char *cuesheet_getFilename(const cuesheet *pCuesheet, int track); +/** + * Get position where the track begins. + * @param pCueSheet Pointer to the cuesheet structure array + * @param track Track nunber + * @return Packed Time for the begining of the track + */ +unsigned long cuesheet_getBeginOfTrack(const cuesheet *pCueSheet, int track); +/** + * Get position where the track ends. + * @param pCueSheet Pointer to the cuesheet structure array + * @param track Track nunber + * @param bNoGap if true, delete pregap for the successive track + * @return Packed Time for the ending of the track + */ +unsigned long cuesheet_getEndOfTrack(const cuesheet *pCueSheet, int track, int bNogap); + +/****** Conversion utility function ******/ +/** + * Convert Packed Time to position as a unit of sample number + * @param ulPackedTime Packed Time value to be converted + * @param ulSamplingFrequency Sampling Frequency[Hz] + * @return Sample number + */ +unsigned long cuesheet_pt2SampleNum(unsigned long ulPackedTime, unsigned long ulSamplingFrequency); +/** + * Convert Packed Time to string. + * @param ulPackedTime Packed Time value to be converted + * @param szTime Pointer to a string + */ +void cuesheet_pt2String(unsigned long ulPackedTime, char *szTime); + +#endif/*_CUESHEET_H_*/ + + + + + + diff -ruN lame-3.90.2/frontend/get_audio.c lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio.c --- lame-3.90.2/frontend/get_audio.c Mon Oct 29 14:00:16 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio.c Fri Apr 4 02:11:16 2003 @@ -66,6 +66,10 @@ #include <dmalloc.h> #endif +#ifdef HAVE_MONKEYS +#include "get_audio_monkeys.h" +#endif + /* global data for get_audio.c. */ int count_samples_carefully; @@ -247,6 +251,14 @@ assert(short_words == 0); } +int get_and_set_tag(lame_global_flags * const gfp) +{ + if (input_format == sf_ape) { + return monkeys_set_id3tag(gfp, musicin); + } + return 0; +} + static int @@ -344,6 +356,13 @@ samples_read = read_samples_ogg( gfp, musicin, buffer16, num_channels ); break; + case sf_ape: + if (buffer != NULL) { + samples_read = monkeys_read_samples(gfp, musicin, samples_to_read, buffer); + } else { + samples_read = monkeys_read_samples16(gfp, musicin, samples_to_read, buf_tmp16); + } + break; default: samples_read = read_samples_pcm(musicin, insamp, num_channels * framesize, @@ -424,7 +443,7 @@ &mp3input_data ); /* * out < 0: error, probably EOF - * out = 0: not possible with lame_decode_fromfile() ??? + * out = 0: not possible with lame_decode_fromfile() ??? * out > 0: number of output samples */ @@ -487,6 +506,29 @@ } +#ifdef HAVE_CUESHEET +int skip_samples(lame_global_flags *gfp, unsigned long ulSamplesSkip) +{ + switch (input_format) { + case sf_raw: + case sf_wave: + return fseek( + musicin, + ulSamplesSkip * (pcmbitwidth / 8) * lame_get_num_channels(gfp), + SEEK_CUR); + break; +#ifdef HAVE_MONKEYS + case sf_ape: + return monkeys_seek_samples(gfp, musicin, ulSamplesSkip); + break; +#endif/*HAVE_MONKEYS*/ + default: + return -1; + } +} +#endif/*HAVE_CUESHEET*/ + + int WriteWaveHeader(FILE * const fp, const int pcmbytes, const int freq, const int channels, const int bits) @@ -1310,9 +1352,13 @@ void CloseSndFile(sound_file_format input, FILE * musicin) { - if (fclose(musicin) != 0) { - fprintf(stderr, "Could not close audio input file\n"); - exit(2); + if (input_format == sf_ape) { + monkeys_decode_finfile(musicin); + } else { + if (fclose(musicin) != 0) { + fprintf(stderr, "Could not close audio input file\n"); + exit(2); + } } } @@ -1386,6 +1432,29 @@ exit(1); #endif } +#ifdef HAVE_MONKEYS + else if (input_format == sf_ape) { + if (-1 == monkeys_decode_initfile(gfp, + inPath, + &musicin, + &mp3input_data)) { + fprintf( + stderr, + "Error reading headers in monkey's input file %s.\n", + inPath); + exit(1); + } + if( -1 == lame_set_num_channels( gfp, mp3input_data.stereo ) ) { + fprintf( stderr, + "Unsupported number of channels: %ud\n", + mp3input_data.stereo ); + exit( 1 ); + } + (void) lame_set_in_samplerate( gfp, mp3input_data.samplerate ); + (void) lame_set_num_samples( gfp, mp3input_data.nsamp ); + count_samples_carefully = 1; + } +#endif else { if (input_format != sf_raw) { parse_file_header(gfp, musicin); diff -ruN lame-3.90.2/frontend/get_audio.h lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio.h --- lame-3.90.2/frontend/get_audio.h Mon Jun 18 11:51:52 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio.h Fri Apr 4 02:11:16 2003 @@ -33,7 +33,8 @@ sf_mp1, /* MPEG Layer 1, aka mpg */ sf_mp2, /* MPEG Layer 2 */ sf_mp3, /* MPEG Layer 3 */ - sf_ogg + sf_ogg, + sf_ape, /* Monkey's Audio */ } sound_file_format; @@ -42,11 +43,21 @@ FILE *init_outfile ( char *outPath, int decode ); void init_infile(lame_global_flags *, char *inPath); void close_infile(void); +int get_and_set_tag(lame_global_flags * const gfp); int get_audio(lame_global_flags *gfp, int buffer[2][1152]); int get_audio16(lame_global_flags *gfp, short buffer[2][1152]); int WriteWaveHeader(FILE * const fp, const int pcmbytes, const int freq, const int channels, const int bits); +/* Modification for cuesheet */ +/** + * Skip samples from current position. + * @param fp lame global flag + * @param ulSamplesSkip samples to skip + * @return 0 if succeeded + */ +int skip_samples(lame_global_flags *gfp, unsigned long ulSamplesSkip); +/* End of modification for cuesheet */ /* the simple lame decoder */ diff -ruN lame-3.90.2/frontend/get_audio_monkeys.cpp lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio_monkeys.cpp --- lame-3.90.2/frontend/get_audio_monkeys.cpp Thu Jan 1 09:00:00 1970 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio_monkeys.cpp Fri Apr 4 02:11:16 2003 @@ -0,0 +1,402 @@ +/* + * Interface for Monkey's Audio + * + * Copyright (c) 2002 nyaochi + * + * Monkey's Audio + * Copyright (C) 2000-2002 by Matthew T. Ashland + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Monkey's Audio. Copyright (C) 2000-2002 by Matthew T. Ashland + * His sample codes also provide me with useful information. Thanks. + */ + +#ifdef _WINDOWS +#include <windows.h> /* LoadLibrary, FreeLibrary, GetProcAddress, etc... */ +#endif /* #ifdef _WINDOWS */ + +#include <stdio.h> +#include <stdlib.h> + +#include <lame.h> /* I think this should not be "lame.h" */ + + +/* this typedefs are used in MACDLL.h (or MACLIB.h) */ +#ifndef __int16 +#define __int16 short +#endif +#ifndef __int32 +#define __int32 long +#endif + +#include "monkeys/MACDll.h" +#include "monkeys/APETag.h" + + + + +/** + * MAC_DLL structure (holds function pointers) + */ +struct tagMAC_DLL +{ + /* APEDecompress functions */ + proc_APEDecompress_Create Create; + proc_APEDecompress_Destroy Destroy; + proc_APEDecompress_GetData GetData; + proc_APEDecompress_Seek Seek; + proc_APEDecompress_GetInfo GetInfo; +}; +typedef struct tagMAC_DLL MAC_DLL; + + +/** + * MAC_FILE structure (holds decompress handle and ID3 tag info) + */ +struct tagMAC_FILE +{ + /** + * handle for APEDecompress interface. + */ + APE_DECOMPRESS_HANDLE hAPEDecompress; + /** + * ID3TAG. + * @memo currently MACDll.dll does not support APE tag. + */ + struct ID3_TAG id3tag; +}; +typedef struct tagMAC_FILE MAC_FILE; + + + + + +/** + * Helper function to get procedure addresses for the functions in DLL. + * @param hMacDll Module instance handle + * @retval pMacDll Pointer to structure MAC_DLL + * @return zero if succeeded. + */ +static int getFunctions(HMODULE hMACDll, MAC_DLL* pMACDll) +{ + /* clear */ + memset(pMACDll, 0, sizeof(MAC_DLL)); + + /* load procedure addresses of the functions */ + if (hMACDll != NULL) + { + pMACDll->Create = (proc_APEDecompress_Create) \ + GetProcAddress(hMACDll, "c_APEDecompress_Create"); + pMACDll->Destroy = (proc_APEDecompress_Destroy) \ + GetProcAddress(hMACDll, "c_APEDecompress_Destroy"); + pMACDll->GetData = (proc_APEDecompress_GetData) \ + GetProcAddress(hMACDll, "c_APEDecompress_GetData"); + pMACDll->Seek = (proc_APEDecompress_Seek) \ + GetProcAddress(hMACDll, "c_APEDecompress_Seek"); + pMACDll->GetInfo = (proc_APEDecompress_GetInfo) \ + GetProcAddress(hMACDll, "c_APEDecompress_GetInfo"); + } + + /* check if all of them are retrieved */ + if ((pMACDll->Create == NULL) || (pMACDll->Destroy == NULL) || + (pMACDll->GetData == NULL) || (pMACDll->Seek == NULL) || + (pMACDll->GetInfo == NULL)) + { + return -1; + } + + return 0; +} + +/** + * Version check for the dll/interface + * @param hMacDll Module instance handle + * @return + */ +static int versionCheckInterface(HMODULE hMACDll) +{ + int nRetVal = -1; + proc_GetInterfaceCompatibility GetInterfaceCompatibility = + (proc_GetInterfaceCompatibility) GetProcAddress( + hMACDll, + "GetInterfaceCompatibility"); + + if (GetInterfaceCompatibility) + { + nRetVal = GetInterfaceCompatibility(MAC_VERSION_NUMBER, TRUE, NULL); + } + + return nRetVal; +} + +/** + * Retrieval of ID3Tag from ape file. + * @param hMacDll Module instance handle + * @param filename Filename + * @retval pID3Tag ID3 tag information + * @return + */ +static int getID3Tag(HMODULE hMACDll, const char *filename, ID3_TAG *pID3Tag) +{ + typedef int (__stdcall * proc_GetID3Tag)(const char * pFilename, ID3_TAG * pID3Tag); + + int nRetVal = -1; + proc_GetID3Tag GetID3Tag = + (proc_GetID3Tag) GetProcAddress( + hMACDll, + "GetID3Tag"); + + if (GetID3Tag) + { + nRetVal = GetID3Tag(filename, pID3Tag); + } + + return nRetVal; +} + + + + +MAC_DLL MACDll; +HMODULE hMACDll; + +#ifdef __cplusplus +extern "C" { +int monkeys_decode_initfile(lame_global_flags* gfp, + const char *filename, + FILE** pfp, + mp3data_struct* mp3data) +{ + int nRetVal; + + hMACDll = LoadLibrary("MACDll.dll"); + if (hMACDll == NULL) + { + return -1; + } + + if (versionCheckInterface(hMACDll) != 0) + { + FreeLibrary(hMACDll); + hMACDll = NULL; + return -1; + } + + if (getFunctions(hMACDll, &MACDll) != 0) + { + FreeLibrary(hMACDll); + hMACDll = NULL; + return -1; + } + + MAC_FILE *pMacFile = (MAC_FILE*)malloc(sizeof(MAC_FILE)); + memset(pMacFile, 0, sizeof(MAC_FILE)); + + /* + * For apl support? + * I do not know the reason, but it seems that MACDLL.dll crashes + * when filename is not passed in the form of full path. + * So I force to convert filename to full pathname. + */ + TCHAR szFullPath[MAX_PATH]; + GetFullPathName(filename, MAX_PATH, szFullPath, NULL); + + pMacFile->hAPEDecompress = MACDll.Create(szFullPath, &nRetVal); + if (!pMacFile->hAPEDecompress) + { + FreeLibrary(hMACDll); + hMACDll = NULL; + return -1; + } + + /* Retrieve ID3TAG from ape file (only ID3v1 because of DLL interface) */ + getID3Tag(hMACDll, szFullPath, &pMacFile->id3tag); + + /* Ugly, but we cannot help casting to FILE pointer */ + *pfp = (FILE *)pMacFile; + + /* Store wave information */ + mp3data->header_parsed = 1; + mp3data->stereo = MACDll.GetInfo( + pMacFile->hAPEDecompress, + APE_INFO_CHANNELS, + 0, 0); + mp3data->samplerate = MACDll.GetInfo( + pMacFile->hAPEDecompress, + APE_INFO_SAMPLE_RATE, + 0, 0); + mp3data->nsamp = MACDll.GetInfo( + pMacFile->hAPEDecompress, + APE_DECOMPRESS_TOTAL_BLOCKS, + 0, 0); + + return 0; +} + +int monkeys_decode_finfile(FILE* fp) +{ + MAC_FILE *pMacFile = (MAC_FILE*)fp; + + MACDll.Destroy(pMacFile->hAPEDecompress); + memset(pMacFile, 0, sizeof(MAC_FILE)); + + FreeLibrary(hMACDll); + hMACDll = NULL; + memset(&MACDll, 0, sizeof(MAC_DLL)); + + return 0; +} + +int monkeys_read_samples(lame_global_flags* gfp, + FILE* musicin, + int samples_to_read, + int pcm[2][1152]) +{ + char buffer[1152*2*sizeof(int)], *p = NULL; + + MAC_FILE* pMacFile = (MAC_FILE*)musicin; + int nRetVal = 0; + int nBlocksRetrieved = 0; + int i, j; + + const int nBits = MACDll.GetInfo(pMacFile->hAPEDecompress, + APE_INFO_BITS_PER_SAMPLE, + 0, 0); + const int nChannels = MACDll.GetInfo(pMacFile->hAPEDecompress, + APE_INFO_CHANNELS, + 0, 0); + const int nBytes = MACDll.GetInfo(pMacFile->hAPEDecompress, + APE_INFO_BYTES_PER_SAMPLE, + 0, 0); + + /* + * Get PCM data into buffer. + */ + nRetVal = MACDll.GetData( + pMacFile->hAPEDecompress, + (char *)buffer, samples_to_read, + &nBlocksRetrieved); + + /* The last address of buffer */ + p = buffer + nBytes * nChannels * nBlocksRetrieved; + /* + * Store PCM data into pcm array. + * This code will be work with at least intel architecture. + */ + for (i = nBlocksRetrieved-1;0 <= i;i--) { + for (j = 1;0 <= j;j--) { + int sample = 0; + if (j < nChannels) { + switch (nBytes) { + case 1: + /* treat carefully unsigned char */ + sample = *((unsigned char *)--p); + sample -= 128; + sample <<= 24; + sample += (127 << 16); + break; + case 2: + p -= 2; + sample = *((short *)p); + sample <<= 16; + break; + case 3: + p -= 2; + sample = *((short *)p); + sample <<= 16; + sample += *((unsigned char *)--p) << 8; + break; + case 4: + /* I don't test this case. */ + p -= 4; + sample = *p; + break; + } + pcm[j][i] = sample; + } + } + } + + return nBlocksRetrieved; +} + +int monkeys_read_samples16(lame_global_flags* gfp, + FILE* musicin, + int samples_to_read, + short int pcm[2][1152]) +{ + short int buffer[1152*2]; + + MAC_FILE* pMacFile = (MAC_FILE*)musicin; + int nRetVal = 0; + int nBlocksRetrieved = 0; + int i, j; + + const int nChannels = MACDll.GetInfo(pMacFile->hAPEDecompress, + APE_INFO_CHANNELS, + 0, 0); + + nRetVal = MACDll.GetData( + pMacFile->hAPEDecompress, + (char *)buffer, samples_to_read, + &nBlocksRetrieved); + + for (i = nBlocksRetrieved-1;0 <= i;i--) { + for (j = 1;0 <= j;j--) { + if (j < nChannels) { + pcm[j][i] = buffer[i * nChannels + j]; + pcm[j][i] <<= 16; + } else { + pcm[j][i] = 0; + } + } + } + + return nBlocksRetrieved; +} + +int monkeys_seek_samples(lame_global_flags* gfp, void *musicin, unsigned long ulSamples) +{ + MAC_FILE* pMacFile = (MAC_FILE*)musicin; + + return MACDll.Seek(pMacFile->hAPEDecompress, (int)ulSamples); +} + +int monkeys_set_id3tag(lame_global_flags* gfp, void *musicin) +{ + MAC_FILE* pMacFile = (MAC_FILE*)musicin; + char buff[5]; + + id3tag_set_title(gfp, pMacFile->id3tag.Title); + id3tag_set_artist(gfp, pMacFile->id3tag.Artist); + id3tag_set_album(gfp, pMacFile->id3tag.Album); + id3tag_set_year(gfp, pMacFile->id3tag.Year); + id3tag_set_comment(gfp, pMacFile->id3tag.Comment); + + itoa((int)pMacFile->id3tag.Track, buff, 10); + id3tag_set_track(gfp, buff); + + itoa((int)pMacFile->id3tag.Genre, buff, 10); + id3tag_set_genre(gfp, buff); + + return 0; +} + +}; /* extern "C" */ +#endif /* #ifdef __cplusplus */ diff -ruN lame-3.90.2/frontend/get_audio_monkeys.h lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio_monkeys.h --- lame-3.90.2/frontend/get_audio_monkeys.h Thu Jan 1 09:00:00 1970 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/get_audio_monkeys.h Fri Apr 4 02:11:16 2003 @@ -0,0 +1,31 @@ +#ifndef __GET_AUDIO_MONKEYS_H__ +#define __GET_AUDIO_MONKEYS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int monkeys_decode_initfile(lame_global_flags* gfp, + const char *filename, + FILE** pfp, + mp3data_struct* mp3data); +int monkeys_decode_finfile(FILE* fp); +int monkeys_read_samples(lame_global_flags* gfp, + FILE* musicin, + int samples_to_read, + int pcm[2][1152]); +int monkeys_read_samples16(lame_global_flags* gfp, + FILE* musicin, + int samples_to_read, + short int pcm[2][1152]); +int monkeys_seek_samples(lame_global_flags* gfp, + void *musicin, + unsigned long ulSamples); +int monkeys_set_id3tag(lame_global_flags* gfp, void *musicin); + + +#ifdef __cplusplus +}; +#endif + +#endif/*__GET_AUDIO_MONKEYS_H__*/ diff -ruN lame-3.90.2/frontend/main.c lame-3.90.2_cuesheet-0.5.2_ape/frontend/main.c --- lame-3.90.2/frontend/main.c Mon Oct 29 14:00:16 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/main.c Fri Apr 11 03:59:41 2003 @@ -76,6 +76,26 @@ #include <dmalloc.h> #endif +#ifdef HAVE_CUESHEET +#include "cuesheet.h" + +struct tag_gf_cuesheet { + /* written by commandline args. */ + char *szFilename; + char *szBaseFilename; + int bNogap; + int bGapless; + int bTag; + int bSameFolder; + int bBaseName; + long nTrackBegin; + long nTrackEnd; + /* written by others. */ + long nMaxTrack; + unsigned long ulNumSamples; +}; +typedef struct tag_gf_cuesheet gf_cuesheet; +#endif/*HAVE_CUESHEET*/ @@ -88,6 +108,228 @@ * ************************************************************************/ +#ifdef HAVE_CUESHEET + +/** + * initialize gf_cuesheet. + * @param pgfcs pointer to gf_cuesheet instance + */ +void init_gf_cueshet(gf_cuesheet* pgfcs) +{ + pgfcs->szFilename = NULL; + pgfcs->szBaseFilename = NULL; + pgfcs->bSameFolder = 0; + pgfcs->bGapless = 0; + pgfcs->bNogap = 0; + pgfcs->bTag = 0; + pgfcs->bBaseName = 1; + pgfcs->nTrackBegin = 1; + pgfcs->nTrackEnd = 0x7FFFFFFF; /* MAX of long */ +} + +/** + * parse options for cuesheet input. + * @param pgfcs pointer to gf_cuesheet instance + * @param argc number of arguments after "CUESHEET" + * @param argv arguments after "CUESHEET" + * @return 0 when succeeded. + */ +int cueshet_parse_args(gf_cuesheet* pgfcs, int argc, char *argv[]) +{ + /* + Syntax of command line args when using cuesheet input: + lame [lame-options] CUESHEET <cuesheet> <output-name> [cuesheet-options] + In this function, + argc is the number of arguments after "CUESHEET"; + argv[0] must be "CUESHEET"; + argv[1] must be a filename of cuesheet; + argv[2] must be a base name or naming rule of output files. + */ + + int i; + + if (argc < 3) { + /* insufficient arguments for cuesheet input */ + fprintf(stderr, "Insufficient arguments for cuesheet input.\n\n"); + return -1; + } + + /* store <cuesheet> and <output-name> */ + pgfcs->szFilename = argv[1]; + pgfcs->szBaseFilename = argv[2]; + + /* parse [cuesheet-options] */ + for (i = 3;i < argc;i++) { + if (strcmp(argv[i], "--gapless") == 0) { + pgfcs->bGapless = 1; + pgfcs->bNogap = 0; + } else if (strcmp(argv[i], "--nogap") == 0) { + pgfcs->bGapless = 0; + pgfcs->bNogap = 1; + } else if (strcmp(argv[i], "--tag") == 0) { + pgfcs->bTag = 1; + } else if (strcmp(argv[i], "--same-folder") == 0) { + pgfcs->bSameFolder = 1; + } else if (strcmp(argv[i], "--naming-rule") == 0) { + pgfcs->bBaseName = 0; + } else if (strcmp(argv[i], "--track") == 0) { + /* parse track number */ + if (++i < argc) { + char *p; + if ((p = strchr(argv[i], '-')) == NULL) { + /* specified as "--track bb" */ + pgfcs->nTrackBegin = pgfcs->nTrackEnd = atoi(argv[i]); + } else { + /* specified as "--track bb-ee" */ + *p = '\0'; + if (*argv[i]) { + pgfcs->nTrackBegin = atoi(argv[i]); + } + if (*(p + 1)) { + pgfcs->nTrackEnd = atoi(p + 1); + } + } + } else { + /* wrong format in option "--track" */ + fprintf( + stderr, + "Wrong format in option --track: %s\n\n", + argv[i]); + return -2; + } + } else { + /* unrecognized options */ + fprintf( + stderr, + "An unrecognized option for cuesheet mode: %s\n\n", + argv[i]); + return -1; + } + } + + /* exit with success */ + return 0; +} + +/** + * print version information of cuesheet input. + * @param fp output stream + */ +void cuesheet_print_version(FILE *fp) +{ + fprintf(fp, "+ Modification for Cuesheet Support Version 0.5.2\n"); +} + +/** + * print usage of cuesheet input. + * @param fp output stream + */ +void cuesheet_print_usage(FILE *fp) +{ + fprintf( + fp, + "USAGE:\n" + " lame [lame-options] CUESHEET <cuesheet> <output-name> [cuesheet-options]\n" + "\n" + "[lame-options] your favorite options for lame\n" + "<cuesheet> cuesheet filename to be processed\n" + "<output-name> base name or naming rule of output files\n" + "[cuesheet-options]\n" + " --naming-rule assume <output-name> to be a naming rule\n" + " available rules (with a prefix %% or $) for naming files:\n" + " %%t (title of the track); %%T (title of the album);\n" + " %%p (performer of the track); %%P (performer of the album);\n" + " %%n (track number).\n" + " by default, assume <output-name> to be a base name\n" + " 01<output-name>.mp3, 02<output-name>.mp3, ...\n" + " --track <tracks> specify tracks to be encoded\n" + " <tracks> must be one of the following formats:\n" + " 1 (only track #1); 1-12 (from #1 to #12);\n" + " -3 (from #1 to #3); 5- (from #5 to last).\n" + " --nogap delete gap between tracks\n" + " --gapless enable gapless encoding (same as \"--nogap\" of lame option)\n" + " --tag add tag infomation from the cuesheet\n" + " --same-folder ignore absolute path of audio source in the cuesheet\n" + "\n" + "EXAMPLE:\n" + " lame --alt-preset standard CUESHEET CDImage.cue album --tag --track 3-4\n" + " lame --alt-preset standard CUESHEET CDImage.cue %%t.mp3 --naming-rule --tag\n" + ); +} + +/** + * generate output filename of each track. + * @param filename [OUT] filename of the track + * @param track track number + * @param pgfcs pointer to gf_cuesheet (options for cuesheet) + * @param pcs pointer to cuesheet (contents of cuesheet) + * @return 0 when succeeded + */ +int make_filename(char *filename, int track, gf_cuesheet *pgfcs, cuesheet *pcs) +{ + /* Null-pointer check */ + if (!filename || !pgfcs || !pcs) { + return -1; + } + /* track range check */ + if (track < pgfcs->nTrackBegin || pgfcs->nTrackEnd < track) { + return -2; + } + + if (pgfcs->bBaseName) { + /* base name mode to generate "##<output-name>.mp3" */ + sprintf(filename, "%02d%s.mp3", track, pgfcs->szBaseFilename); + } else { + /* naming rule mode */ + const char *p = pgfcs->szBaseFilename; + while (*p) { + if (*p == '%' || *p == '$') { + /* rules */ + char prefix = *p; + char szTrack[20]; + const char *src = NULL; + p++; + if (*p == 't') { + src = pcs[track].szTitle; + } else if (*p == 'p') { + src = pcs[track].szPerformer; + } else if (*p == 'T') { + src = pcs[0].szTitle; + } else if (*p == 'P') { + src = pcs[0].szPerformer; + } else if (*p == 'n') { + sprintf(szTrack, "%02d", track); + src = szTrack; + } else if (*p == prefix) { + *filename++ = prefix; + } else { + return -1; + } + + if (src) { + /* copy src to filename */ + while (*src) { + *filename++ = *src++; + } + } + } else { + /* other characters */ + *filename++ = *p; + } + p++; + } + + /* make sure to add '\0' */ + *filename = '\0'; + } + + /* exit with success */ + return 0; +} + +#endif/*HAVE_CUESHEET*/ + + int parse_args_from_string(lame_global_flags * const gfp, const char *p, char *inPath, char *outPath) @@ -436,7 +678,10 @@ imp3 = lame_encode_flush_nogap(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */ /* reinitialize bitstream for next encoding. this is normally done * by lame_init_params(), but we cannot call that routine twice */ +#ifdef HAVE_CUESHEET +#else lame_init_bitstream(gf); +#endif } else { imp3 = lame_encode_flush(gf, mp3buffer, sizeof(mp3buffer)); /* may return one more mp3 frame */ } @@ -594,6 +839,13 @@ int max_nogap = MAX_NOGAP; char *nogap_inPath[MAX_NOGAP]; +#ifdef HAVE_CUESHEET + int cs_argc = 0; + cuesheet* cs = NULL; + char inPathAndPos[MAX_NAME_SIZE * 2]; + gf_cuesheet gfcs; +#endif/*HAVE_CUESHEET*/ + int i; FILE *outf; @@ -626,6 +878,17 @@ } memset(inPath, 0, sizeof(inPath)); + +#ifdef HAVE_CUESHEET + cuesheet_print_version(stderr); +#endif +#ifdef HAVE_MONKEYS + fprintf(stderr, "+ Modification for Monkey's Audio (APE) Support.\n"); +#endif +#ifdef HAVE_NYAOCHI_MODIFICATION + fprintf(stderr, " Available at http://www.geocities.com/nyaochi2000/lame/\n"); + fprintf(stderr, "\n"); +#endif /* initialize libmp3lame */ input_format = sf_unknown; @@ -638,6 +901,26 @@ return 1; } +#ifdef HAVE_CUESHEET + init_gf_cueshet(&gfcs); + + /* + search a word, 'CUESHEET' in the command-line args. + if we found one, activate cuesheet input mode. + */ + cs_argc = argc; + for (i = 0;i < argc;i++) { + if (strcmp(argv[i], "CUESHEET") == 0) { + if (cueshet_parse_args(&gfcs, argc - i, argv + i) < 0) { + cuesheet_print_usage(stderr); + return -1; + } + argc = i + 1; + break; + } + } +#endif/*HAVE_CUESHEET*/ + /* parse the command line arguments, setting various flags in the * struct 'gf'. If you want to parse your own arguments, * or call libmp3lame from a program which uses a GUI to set arguments, @@ -656,9 +939,56 @@ strncpy(nogapdir,outPath,MAX_NAME_SIZE); nogapout = 1; } + +#ifdef HAVE_CUESHEET + if (gfcs.szFilename != NULL) { + /* cuesheet input mode */ + if (max_nogap > 0) { + /* currently, we cannot use with --nogap option */ + fprintf( + stderr, + "ERROR: Do not put \"--nogap\" in lame options when using cuesheet input mode.\n" + " Try \"--gapless\" option instead in cuesheet options.\n" + ); + return -1; + } + /* open cuesheet */ + cs = cuesheet_open(gfcs.szFilename, gfcs.bSameFolder); + if (cs == NULL) { + fprintf(stderr, "ERROR: Cannot open %s\n", gfcs.szFilename); + return -1; + } + gfcs.nMaxTrack = cs[0].nTrack; + gfcs.nTrackBegin = gfcs.nTrackBegin < 1 ? 1 : gfcs.nTrackBegin; + gfcs.nTrackEnd = gfcs.nTrackEnd > gfcs.nMaxTrack ? gfcs.nMaxTrack : gfcs.nTrackEnd; + max_nogap = gfcs.nMaxTrack - 1; + } +#endif/*HAVE_CUESHEET*/ /* initialize input file. This also sets samplerate and as much other data on the input file as available in the headers */ +#ifdef HAVE_CUESHEET + if (gfcs.szFilename != NULL) { + /* set tag information for the first track. + We should call these functions before init_files() call. + */ + if (gfcs.bTag) { + int i = gfcs.nTrackBegin; + char szTrackNum[34]; + id3tag_set_title(gf, cs[i].szTitle); + id3tag_set_artist(gf, cs[i].szPerformer); + id3tag_set_album(gf, cs[0].szTitle); + itoa(i, szTrackNum, 10); + id3tag_set_track(gf, szTrackNum); + } + + /* generate an output file name */ + make_filename(outPath, gfcs.nTrackBegin, &gfcs, cs); + outf = init_files(gf, cs[gfcs.nTrackBegin].szFileName, outPath); + /* retrieve number of samples (track length in samples) */ + gfcs.ulNumSamples = lame_get_num_samples(gf); + } else { +#endif/*HAVE_CUESHEET*/ if (max_nogap > 0) { /* for nogap encoding of multiple input files, it is not possible to * specify the output file name, only an optional output directory. */ @@ -672,6 +1002,9 @@ else { outf = init_files(gf, inPath, outPath); } +#ifdef HAVE_CUESHEET + } +#endif/*HAVE_CUESHEET*/ if (outf == NULL) { return -1; } @@ -710,6 +1043,99 @@ } else { +#ifdef HAVE_CUESHEET + if (cs != NULL) { + /* loop from a start track to an end track */ + for (i = gfcs.nTrackBegin; i <= gfcs.nTrackEnd;++i) { + int use_flush_nogap = gfcs.bGapless && (i != gfcs.nTrackEnd); + unsigned long ulPtBegin = cuesheet_getBeginOfTrack(cs, i); + unsigned long ulPtEnd = cuesheet_getEndOfTrack(cs, i, gfcs.bNogap); + unsigned long ulSampleBegin = 0; + unsigned long ulSampleEnd = 0; + unsigned long ulSamples = 0; + char szSampleBegin[9]; + char szSampleEnd[9]; + char szTrackNum[34]; + + if (i > gfcs.nTrackBegin) { + if (gfcs.bTag) { + id3tag_set_title(gf, cs[i].szTitle); + id3tag_set_artist(gf, cs[i].szPerformer); + id3tag_set_album(gf, cs[0].szTitle); + itoa(i, szTrackNum, 10); + id3tag_set_track(gf, szTrackNum); + } + + /* generate an output file name */ + make_filename(outPath, i, &gfcs, cs); + /* note: if init_files changes anything, like + samplerate, num_channels, etc, we are screwed */ + outf = init_files(gf, cs[i].szFileName, outPath); + gfcs.ulNumSamples = lame_get_num_samples(gf); + /* reinitialize bitstream for next encoding is normally done + * by lame_init_params(), but we cannot call that routine twice */ + lame_init_bitstream(gf); + } + if (outf == NULL) { + return -1; + } + + /* retrieve the beginning of the track in samples */ + ulSampleBegin = cuesheet_pt2SampleNum(ulPtBegin, lame_get_in_samplerate(gf)); + /* the same in string format */ + cuesheet_pt2String(ulPtBegin, szSampleBegin); + if (ulPtEnd == CS_PT_END) { + /* the last track in cuesheet */ + ulSampleEnd = gfcs.ulNumSamples; + strcpy(szSampleEnd, "LAST"); + } else { + ulSampleEnd = cuesheet_pt2SampleNum(ulPtEnd, lame_get_in_samplerate(gf)); + cuesheet_pt2String(ulPtEnd, szSampleEnd); + } + /* generate information of input file and position */ + sprintf( + inPathAndPos, + "%s [%s, %s)", + cs[i].szFileName, + szSampleBegin, + szSampleEnd + ); + + /* calculate number of samples to be encoded */ + if (ulSampleBegin < ulSampleEnd) { + ulSamples = ulSampleEnd - ulSampleBegin; + if (gfcs.ulNumSamples < ulSamples) { + ulSamples = gfcs.ulNumSamples; + } + } else { + fprintf(stderr, "ERROR: fatal error in cuesheet.\n"); + return -1; + } + + /* set number of samples to fool audio read routine. */ + lame_set_num_samples(gf, ulSamples); + /* seek to the beginning of the current track */ + skip_samples(gf, ulSampleBegin); + + /* encode with flash for nogap */ + brhist_init_package(gf); + if (tag_by_input) { + get_and_set_tag(gf); + } + + ret = + lame_encoder(gf, outf, use_flush_nogap, inPathAndPos, + outPath); + if (silent<=0) ReportLameTagProgress(gf,1); + lame_mp3_tags_fid(gf, outf); /* add VBR tags to mp3 file */ + if (silent<=0) ReportLameTagProgress(gf,0); + + fclose(outf); /* close the output file */ + close_infile(); /* close the input file */ + } + lame_close(gf); + } else { +#endif if (max_nogap > 0) { /* * encode multiple input files using nogap option @@ -721,6 +1147,11 @@ /* note: if init_files changes anything, like samplerate, num_channels, etc, we are screwed */ outf = init_files(gf, nogap_inPath[i], outPath); +#ifdef HAVE_CUESHEET + /* reinitialize bitstream for next encoding is normally done + * by lame_init_params(), but we cannot call that routine twice */ + lame_init_bitstream(gf); +#endif/*HAVE_CUESHEET*/ } brhist_init_package(gf); ret = @@ -752,6 +1183,9 @@ close_infile(); /* close the input file */ lame_close(gf); } +#ifdef HAVE_CUESHEET + } +#endif/*HAVE_CUESHEET*/ } return ret; } diff -ruN lame-3.90.2/frontend/main.h lame-3.90.2_cuesheet-0.5.2_ape/frontend/main.h --- lame-3.90.2/frontend/main.h Mon Oct 29 14:00:16 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/main.h Fri Apr 4 02:11:16 2003 @@ -47,6 +47,7 @@ #define order_unknown 2 extern int in_endian; extern int in_bitwidth; +extern int tag_by_input; #define Min(A, B) ((A) < (B) ? (A) : (B)) #define Max(A, B) ((A) > (B) ? (A) : (B)) diff -ruN lame-3.90.2/frontend/parse.c lame-3.90.2_cuesheet-0.5.2_ape/frontend/parse.c --- lame-3.90.2/frontend/parse.c Sun Dec 23 15:51:14 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/frontend/parse.c Fri Apr 4 02:11:16 2003 @@ -84,6 +84,7 @@ int in_unsigned=0; int in_endian=order_littleEndian; int in_bitwidth=16; +int tag_by_input=0; /** @@ -383,6 +384,9 @@ #if defined(HAVE_VORBIS) " --ogginput input file is a Ogg Vorbis file\n" #endif +#if defined(HAVE_MONKEYS) + " --apeinput input file is a Monkey's Audio file\n" +#endif " --nogap <file1> <file2> <...>\n" " gapless encoding for a set of contiguous files\n" " --nogapout <dir>\n" @@ -533,6 +537,7 @@ " --space-id3v1 pad version 1 tag with spaces instead of nulls\n" " --pad-id3v2 pad version 2 tag with extra 128 bytes\n" " --genre-list print alphabetically sorted ID3 genre list and exit\n" + " --tag-by-input tag automatically by information in input file\n" "\n" " Note: A version 2 tag will NOT be added unless one of the input fields\n" " won't fit in a version 1 tag (e.g. the title string is longer than 30\n" @@ -1429,6 +1434,13 @@ fprintf(stderr,"Error: LAME not compiled with Vorbis support\n"); return -1; #endif + T_ELIF ("apeinput") +#if defined(HAVE_MONKEYS) + input_format=sf_ape; +#else + fprintf(stderr,"Error: LAME not compiled with Monkey's Audio support\n"); + return -1; +#endif T_ELIF ("ogg") #if defined(HAVE_VORBIS_ENCODER) (void) lame_set_ogg( gfp, 1 ); @@ -1593,6 +1605,9 @@ T_ELIF ("genre-list") id3tag_genre_list(genre_list_handler, NULL); return -2; + + T_ELIF ("tag-by-input") + tag_by_input = 1; T_ELIF ("lowpass") val = atof( nextArg ); diff -ruN lame-3.90.2/libmp3lame/lame.c lame-3.90.2_cuesheet-0.5.2_ape/libmp3lame/lame.c --- lame-3.90.2/libmp3lame/lame.c Thu Dec 13 23:00:58 2001 +++ lame-3.90.2_cuesheet-0.5.2_ape/libmp3lame/lame.c Fri Apr 4 02:11:16 2003 @@ -1819,6 +1819,9 @@ { lame_internal_flags *gfc = gfp->internal_flags; flush_bitstream(gfp); +#ifdef HAVE_CUESHEET + id3tag_write_v1(gfp); +#endif return copy_buffer(gfc,mp3buffer, mp3buffer_size,1); } |
送花文章: 3,
|
向 psac 送花的會員:
|
zhangsijie (2010-09-18)
感謝您發表一篇好文章 |