@@ -0,0 +1,340 @@ | |||
GNU GENERAL PUBLIC LICENSE | |||
Version 2, June 1991 | |||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
Everyone is permitted to copy and distribute verbatim copies | |||
of this license document, but changing it is not allowed. | |||
Preamble | |||
The licenses for most software are designed to take away your | |||
freedom to share and change it. By contrast, the GNU General Public | |||
License is intended to guarantee your freedom to share and change free | |||
software--to make sure the software is free for all its users. This | |||
General Public License applies to most of the Free Software | |||
Foundation's software and to any other program whose authors commit to | |||
using it. (Some other Free Software Foundation software is covered by | |||
the GNU Library General Public License instead.) You can apply it to | |||
your programs, too. | |||
When we speak of free software, we are referring to freedom, not | |||
price. Our General Public Licenses are designed to make sure that you | |||
have the freedom to distribute copies of free software (and charge for | |||
this service if you wish), that you receive source code or can get it | |||
if you want it, that you can change the software or use pieces of it | |||
in new free programs; and that you know you can do these things. | |||
To protect your rights, we need to make restrictions that forbid | |||
anyone to deny you these rights or to ask you to surrender the rights. | |||
These restrictions translate to certain responsibilities for you if you | |||
distribute copies of the software, or if you modify it. | |||
For example, if you distribute copies of such a program, whether | |||
gratis or for a fee, you must give the recipients all the rights that | |||
you have. You must make sure that they, too, receive or can get the | |||
source code. And you must show them these terms so they know their | |||
rights. | |||
We protect your rights with two steps: (1) copyright the software, and | |||
(2) offer you this license which gives you legal permission to copy, | |||
distribute and/or modify the software. | |||
Also, for each author's protection and ours, we want to make certain | |||
that everyone understands that there is no warranty for this free | |||
software. If the software is modified by someone else and passed on, we | |||
want its recipients to know that what they have is not the original, so | |||
that any problems introduced by others will not reflect on the original | |||
authors' reputations. | |||
Finally, any free program is threatened constantly by software | |||
patents. We wish to avoid the danger that redistributors of a free | |||
program will individually obtain patent licenses, in effect making the | |||
program proprietary. To prevent this, we have made it clear that any | |||
patent must be licensed for everyone's free use or not licensed at all. | |||
The precise terms and conditions for copying, distribution and | |||
modification follow. | |||
GNU GENERAL PUBLIC LICENSE | |||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
0. This License applies to any program or other work which contains | |||
a notice placed by the copyright holder saying it may be distributed | |||
under the terms of this General Public License. The "Program", below, | |||
refers to any such program or work, and a "work based on the Program" | |||
means either the Program or any derivative work under copyright law: | |||
that is to say, a work containing the Program or a portion of it, | |||
either verbatim or with modifications and/or translated into another | |||
language. (Hereinafter, translation is included without limitation in | |||
the term "modification".) Each licensee is addressed as "you". | |||
Activities other than copying, distribution and modification are not | |||
covered by this License; they are outside its scope. The act of | |||
running the Program is not restricted, and the output from the Program | |||
is covered only if its contents constitute a work based on the | |||
Program (independent of having been made by running the Program). | |||
Whether that is true depends on what the Program does. | |||
1. You may copy and distribute verbatim copies of the Program's | |||
source code as you receive it, in any medium, provided that you | |||
conspicuously and appropriately publish on each copy an appropriate | |||
copyright notice and disclaimer of warranty; keep intact all the | |||
notices that refer to this License and to the absence of any warranty; | |||
and give any other recipients of the Program a copy of this License | |||
along with the Program. | |||
You may charge a fee for the physical act of transferring a copy, and | |||
you may at your option offer warranty protection in exchange for a fee. | |||
2. You may modify your copy or copies of the Program or any portion | |||
of it, thus forming a work based on the Program, and copy and | |||
distribute such modifications or work under the terms of Section 1 | |||
above, provided that you also meet all of these conditions: | |||
a) You must cause the modified files to carry prominent notices | |||
stating that you changed the files and the date of any change. | |||
b) You must cause any work that you distribute or publish, that in | |||
whole or in part contains or is derived from the Program or any | |||
part thereof, to be licensed as a whole at no charge to all third | |||
parties under the terms of this License. | |||
c) If the modified program normally reads commands interactively | |||
when run, you must cause it, when started running for such | |||
interactive use in the most ordinary way, to print or display an | |||
announcement including an appropriate copyright notice and a | |||
notice that there is no warranty (or else, saying that you provide | |||
a warranty) and that users may redistribute the program under | |||
these conditions, and telling the user how to view a copy of this | |||
License. (Exception: if the Program itself is interactive but | |||
does not normally print such an announcement, your work based on | |||
the Program is not required to print an announcement.) | |||
These requirements apply to the modified work as a whole. If | |||
identifiable sections of that work are not derived from the Program, | |||
and can be reasonably considered independent and separate works in | |||
themselves, then this License, and its terms, do not apply to those | |||
sections when you distribute them as separate works. But when you | |||
distribute the same sections as part of a whole which is a work based | |||
on the Program, the distribution of the whole must be on the terms of | |||
this License, whose permissions for other licensees extend to the | |||
entire whole, and thus to each and every part regardless of who wrote it. | |||
Thus, it is not the intent of this section to claim rights or contest | |||
your rights to work written entirely by you; rather, the intent is to | |||
exercise the right to control the distribution of derivative or | |||
collective works based on the Program. | |||
In addition, mere aggregation of another work not based on the Program | |||
with the Program (or with a work based on the Program) on a volume of | |||
a storage or distribution medium does not bring the other work under | |||
the scope of this License. | |||
3. You may copy and distribute the Program (or a work based on it, | |||
under Section 2) in object code or executable form under the terms of | |||
Sections 1 and 2 above provided that you also do one of the following: | |||
a) Accompany it with the complete corresponding machine-readable | |||
source code, which must be distributed under the terms of Sections | |||
1 and 2 above on a medium customarily used for software interchange; or, | |||
b) Accompany it with a written offer, valid for at least three | |||
years, to give any third party, for a charge no more than your | |||
cost of physically performing source distribution, a complete | |||
machine-readable copy of the corresponding source code, to be | |||
distributed under the terms of Sections 1 and 2 above on a medium | |||
customarily used for software interchange; or, | |||
c) Accompany it with the information you received as to the offer | |||
to distribute corresponding source code. (This alternative is | |||
allowed only for noncommercial distribution and only if you | |||
received the program in object code or executable form with such | |||
an offer, in accord with Subsection b above.) | |||
The source code for a work means the preferred form of the work for | |||
making modifications to it. For an executable work, complete source | |||
code means all the source code for all modules it contains, plus any | |||
associated interface definition files, plus the scripts used to | |||
control compilation and installation of the executable. However, as a | |||
special exception, the source code distributed need not include | |||
anything that is normally distributed (in either source or binary | |||
form) with the major components (compiler, kernel, and so on) of the | |||
operating system on which the executable runs, unless that component | |||
itself accompanies the executable. | |||
If distribution of executable or object code is made by offering | |||
access to copy from a designated place, then offering equivalent | |||
access to copy the source code from the same place counts as | |||
distribution of the source code, even though third parties are not | |||
compelled to copy the source along with the object code. | |||
4. You may not copy, modify, sublicense, or distribute the Program | |||
except as expressly provided under this License. Any attempt | |||
otherwise to copy, modify, sublicense or distribute the Program is | |||
void, and will automatically terminate your rights under this License. | |||
However, parties who have received copies, or rights, from you under | |||
this License will not have their licenses terminated so long as such | |||
parties remain in full compliance. | |||
5. You are not required to accept this License, since you have not | |||
signed it. However, nothing else grants you permission to modify or | |||
distribute the Program or its derivative works. These actions are | |||
prohibited by law if you do not accept this License. Therefore, by | |||
modifying or distributing the Program (or any work based on the | |||
Program), you indicate your acceptance of this License to do so, and | |||
all its terms and conditions for copying, distributing or modifying | |||
the Program or works based on it. | |||
6. Each time you redistribute the Program (or any work based on the | |||
Program), the recipient automatically receives a license from the | |||
original licensor to copy, distribute or modify the Program subject to | |||
these terms and conditions. You may not impose any further | |||
restrictions on the recipients' exercise of the rights granted herein. | |||
You are not responsible for enforcing compliance by third parties to | |||
this License. | |||
7. If, as a consequence of a court judgment or allegation of patent | |||
infringement or for any other reason (not limited to patent issues), | |||
conditions are imposed on you (whether by court order, agreement or | |||
otherwise) that contradict the conditions of this License, they do not | |||
excuse you from the conditions of this License. If you cannot | |||
distribute so as to satisfy simultaneously your obligations under this | |||
License and any other pertinent obligations, then as a consequence you | |||
may not distribute the Program at all. For example, if a patent | |||
license would not permit royalty-free redistribution of the Program by | |||
all those who receive copies directly or indirectly through you, then | |||
the only way you could satisfy both it and this License would be to | |||
refrain entirely from distribution of the Program. | |||
If any portion of this section is held invalid or unenforceable under | |||
any particular circumstance, the balance of the section is intended to | |||
apply and the section as a whole is intended to apply in other | |||
circumstances. | |||
It is not the purpose of this section to induce you to infringe any | |||
patents or other property right claims or to contest validity of any | |||
such claims; this section has the sole purpose of protecting the | |||
integrity of the free software distribution system, which is | |||
implemented by public license practices. Many people have made | |||
generous contributions to the wide range of software distributed | |||
through that system in reliance on consistent application of that | |||
system; it is up to the author/donor to decide if he or she is willing | |||
to distribute software through any other system and a licensee cannot | |||
impose that choice. | |||
This section is intended to make thoroughly clear what is believed to | |||
be a consequence of the rest of this License. | |||
8. If the distribution and/or use of the Program is restricted in | |||
certain countries either by patents or by copyrighted interfaces, the | |||
original copyright holder who places the Program under this License | |||
may add an explicit geographical distribution limitation excluding | |||
those countries, so that distribution is permitted only in or among | |||
countries not thus excluded. In such case, this License incorporates | |||
the limitation as if written in the body of this License. | |||
9. The Free Software Foundation may publish revised and/or new versions | |||
of the General Public License from time to time. Such new versions will | |||
be similar in spirit to the present version, but may differ in detail to | |||
address new problems or concerns. | |||
Each version is given a distinguishing version number. If the Program | |||
specifies a version number of this License which applies to it and "any | |||
later version", you have the option of following the terms and conditions | |||
either of that version or of any later version published by the Free | |||
Software Foundation. If the Program does not specify a version number of | |||
this License, you may choose any version ever published by the Free Software | |||
Foundation. | |||
10. If you wish to incorporate parts of the Program into other free | |||
programs whose distribution conditions are different, write to the author | |||
to ask for permission. For software which is copyrighted by the Free | |||
Software Foundation, write to the Free Software Foundation; we sometimes | |||
make exceptions for this. Our decision will be guided by the two goals | |||
of preserving the free status of all derivatives of our free software and | |||
of promoting the sharing and reuse of software generally. | |||
NO WARRANTY | |||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |||
REPAIR OR CORRECTION. | |||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |||
POSSIBILITY OF SUCH DAMAGES. | |||
END OF TERMS AND CONDITIONS | |||
How to Apply These Terms to Your New Programs | |||
If you develop a new program, and you want it to be of the greatest | |||
possible use to the public, the best way to achieve this is to make it | |||
free software which everyone can redistribute and change under these terms. | |||
To do so, attach the following notices to the program. It is safest | |||
to attach them to the start of each source file to most effectively | |||
convey the exclusion of warranty; and each file should have at least | |||
the "copyright" line and a pointer to where the full notice is found. | |||
<one line to give the program's name and a brief idea of what it does.> | |||
Copyright (C) <year> <name of author> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program 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 General Public License for more details. | |||
You should have received a copy of the GNU General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
Also add information on how to contact you by electronic and paper mail. | |||
If the program is interactive, make it output a short notice like this | |||
when it starts in an interactive mode: | |||
Gnomovision version 69, Copyright (C) year name of author | |||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |||
This is free software, and you are welcome to redistribute it | |||
under certain conditions; type `show c' for details. | |||
The hypothetical commands `show w' and `show c' should show the appropriate | |||
parts of the General Public License. Of course, the commands you use may | |||
be called something other than `show w' and `show c'; they could even be | |||
mouse-clicks or menu items--whatever suits your program. | |||
You should also get your employer (if you work as a programmer) or your | |||
school, if any, to sign a "copyright disclaimer" for the program, if | |||
necessary. Here is a sample; alter the names: | |||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |||
`Gnomovision' (which makes passes at compilers) written by James Hacker. | |||
<signature of Ty Coon>, 1 April 1989 | |||
Ty Coon, President of Vice | |||
This General Public License does not permit incorporating your program into | |||
proprietary programs. If your program is a subroutine library, you may | |||
consider it more useful to permit linking proprietary applications with the | |||
library. If this is what you want to do, use the GNU Library General | |||
Public License instead of this License. |
@@ -0,0 +1,6 @@ | |||
SUBDIRS= lib tools man | |||
all install uninstall clean: | |||
for dir in $(SUBDIRS) ; do \ | |||
(cd $$dir && $(MAKE) $@) ; \ | |||
done |
@@ -0,0 +1,22 @@ | |||
cuetools README | |||
cuetools is a set of utilites for working with cue and toc files. | |||
RELEASE NOTES | |||
* cuetools-1.x is a significant code rewrite of 0.x. The cue/toc parsing code | |||
has been reimplimented in lex/yacc. | |||
* cuerename has been replaced by the more general utility cueprint. | |||
* Usage syntax of the utilites has changed. See the respective man pages. | |||
INSTALL | |||
Building requires GNU Make. Run `make install' to install cuetools into the | |||
default location of /usr/local. The Makefiles also support both the prefix and | |||
DESTDIR variables. | |||
AUTHOR | |||
Svend Sorensen <ssorensen@freeshell.org> | |||
SEE ALSO | |||
cuetools website - http://cuetools.sourceforge.net | |||
Cdrdao website - http://cdrdao.sourceforge.net | |||
cdrdao(1) man page - description of toc file format | |||
shntool website - http://www.etree.org/shnutils/shntool/ |
@@ -0,0 +1,44 @@ | |||
YFLAGS+= -d | |||
OBJS= cd.o cdtext.o time.o cuefile.o | |||
CUE_OBJS= cue_parse.o cue_scan.o cue_print.o | |||
TOC_OBJS= toc_parse.o toc_scan.o toc_print.o | |||
toc_scan.c: LFLAGS+= -Ptoc_yy | |||
cue_scan.c: LFLAGS+= -Pcue_yy | |||
toc_parse.c: YFLAGS+= -p toc_yy | |||
cue_parse.c: YFLAGS+= -p cue_yy | |||
TARGETS= libcuefile.a | |||
all: $(TARGETS) | |||
libcuefile.a: libcuefile.a($(OBJS) $(CUE_OBJS) $(TOC_OBJS)) | |||
%.c: %.y | |||
$(YACC) -o $@ $(YFLAGS) $< | |||
install: all | |||
uninstall: | |||
clean: | |||
rm -f $(TARGETS) | |||
rm -f *.o *.a *.core *.output | |||
rm -f toc_scan.c toc_parse.c toc_parse.h | |||
rm -f cue_scan.c cue_parse.c cue_parse.h | |||
# dependancies | |||
# generated with `gcc -MM *.c' | |||
# after building lex and yacc .c files | |||
cd.o: cd.c cd.h cdtext.h | |||
cdtext.o: cdtext.c cdtext.h | |||
cuefile.o: cuefile.c cuefile.h cd.h cdtext.h cue.h toc.h | |||
cue_parse.o: cue_parse.c cd.h cdtext.h time.h | |||
cue_print.o: cue_print.c cd.h cdtext.h time.h | |||
cue_scan.o: cue_scan.c cd.h cdtext.h cue_parse.h | |||
time.o: time.c | |||
toc_parse.o: toc_parse.c cd.h cdtext.h time.h | |||
toc_print.o: toc_print.c cd.h cdtext.h time.h | |||
toc_scan.o: toc_scan.c cd.h cdtext.h toc_parse.h |
@@ -0,0 +1,329 @@ | |||
/* | |||
* cd.c -- cd functions | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
typedef struct Data Data; | |||
struct Data { | |||
int type; /* DataType */ | |||
char *name; /* data source name */ | |||
long start; /* start time for data */ | |||
long length; /* length of data */ | |||
}; | |||
struct Track { | |||
Data zero_pre; /* pre-gap generated with zero data */ | |||
Data file; /* track data file */ | |||
Data zero_post; /* post-gap generated with zero data */ | |||
int mode; /* track mode */ | |||
int sub_mode; /* sub-channel mode */ | |||
int flags; /* flags */ | |||
char *isrc; /* IRSC Code (5.22.4) 12 bytes */ | |||
Cdtext *cdtext; /* CD-TEXT */ | |||
int nindex; /* number of indexes */ | |||
long index[MAXINDEX]; /* indexes (in frames) (5.29.2.5) | |||
* relative to start of track | |||
* index[0] should always be zero */ | |||
}; | |||
struct Cd { | |||
int mode; /* disc mode */ | |||
char *catalog; /* Media Catalog Number (5.22.3) */ | |||
Cdtext *cdtext; /* CD-TEXT */ | |||
int ntrack; /* number of tracks in album */ | |||
Track *track[MAXTRACK]; /* array of tracks */ | |||
}; | |||
Cd *cd_init () | |||
{ | |||
Cd *cd = NULL; | |||
cd = malloc(sizeof(Cd)); | |||
if(NULL == cd) { | |||
fprintf(stderr, "unable to create cd\n"); | |||
} else { | |||
cd->mode = MODE_CD_DA; | |||
cd->catalog = NULL; | |||
cd->cdtext = cdtext_init(); | |||
cd->ntrack = 0; | |||
} | |||
return cd; | |||
} | |||
Track *track_init () | |||
{ | |||
Track *track = NULL; | |||
track = malloc(sizeof(Track)); | |||
if (NULL == track) { | |||
fprintf(stderr, "unable to create track\n"); | |||
} else { | |||
track->zero_pre.type = DATA_ZERO; | |||
track->zero_pre.name = NULL; | |||
track->zero_pre.start = 0; | |||
track->zero_pre.length = 0; | |||
track->file.type = DATA_AUDIO; | |||
track->file.name = NULL; | |||
track->file.start = 0; | |||
track->file.length = 0; | |||
track->zero_post.type = DATA_ZERO; | |||
track->zero_post.name = NULL; | |||
track->zero_post.start = 0; | |||
track->zero_post.length = 0; | |||
track->mode = MODE_AUDIO; | |||
track->sub_mode = SUB_MODE_RW; | |||
track->flags = FLAG_NONE; | |||
track->isrc = NULL; | |||
track->cdtext = cdtext_init(); | |||
track->nindex = 0; | |||
} | |||
return track; | |||
} | |||
/* | |||
* cd structure functions | |||
*/ | |||
void cd_set_mode (Cd *cd, int mode) | |||
{ | |||
cd->mode = mode; | |||
} | |||
int cd_get_mode (Cd *cd) | |||
{ | |||
return cd->mode; | |||
} | |||
void cd_set_catalog (Cd *cd, char *catalog) | |||
{ | |||
if (cd->catalog) | |||
free(cd->catalog); | |||
cd->catalog = strdup(catalog); | |||
} | |||
char *cd_get_catalog (Cd *cd) | |||
{ | |||
return cd->catalog; | |||
} | |||
Cdtext *cd_get_cdtext (Cd *cd) | |||
{ | |||
return cd->cdtext; | |||
} | |||
Track *cd_add_track (Cd *cd) | |||
{ | |||
if (MAXTRACK - 1 > cd->ntrack) | |||
cd->ntrack++; | |||
else | |||
fprintf(stderr, "too many tracks\n"); | |||
/* this will reinit last track if there were too many */ | |||
cd->track[cd->ntrack - 1] = track_init(); | |||
return cd->track[cd->ntrack - 1]; | |||
} | |||
int cd_get_ntrack (Cd *cd) | |||
{ | |||
return cd->ntrack; | |||
} | |||
Track *cd_get_track (Cd *cd, int i) | |||
{ | |||
if (0 < i <= cd->ntrack) | |||
return cd->track[i - 1]; | |||
return NULL; | |||
} | |||
/* | |||
* track structure functions | |||
*/ | |||
void track_set_filename (Track *track, char *filename) | |||
{ | |||
if (track->file.name) | |||
free(track->file.name); | |||
track->file.name = strdup(filename); | |||
} | |||
char *track_get_filename (Track *track) | |||
{ | |||
return track->file.name; | |||
} | |||
void track_set_start (Track *track, long start) | |||
{ | |||
track->file.start = start; | |||
} | |||
long track_get_start (Track *track) | |||
{ | |||
return track->file.start; | |||
} | |||
void track_set_length (Track *track, long length) | |||
{ | |||
track->file.length = length; | |||
} | |||
long track_get_length (Track *track) | |||
{ | |||
return track->file.length; | |||
} | |||
void track_set_mode (Track *track, int mode) | |||
{ | |||
track->mode = mode; | |||
} | |||
int track_get_mode (Track *track) | |||
{ | |||
return track->mode; | |||
} | |||
void track_set_sub_mode (Track *track, int sub_mode) | |||
{ | |||
track->sub_mode = sub_mode; | |||
} | |||
int track_get_sub_mode (Track *track) | |||
{ | |||
return track->sub_mode; | |||
} | |||
void track_set_flag (Track *track, int flag) | |||
{ | |||
track->flags |= flag; | |||
} | |||
void track_clear_flag (Track *track, int flag) | |||
{ | |||
track->flags &= ~flag; | |||
} | |||
int track_is_set_flag (Track *track, int flag) | |||
{ | |||
return track->flags & flag; | |||
} | |||
void track_set_zero_pre (Track *track, long length) | |||
{ | |||
track->zero_pre.length = length; | |||
} | |||
long track_get_zero_pre (Track *track) | |||
{ | |||
return track->zero_pre.length; | |||
} | |||
void track_set_zero_post (Track *track, long length) | |||
{ | |||
track->zero_post.length = length; | |||
} | |||
long track_get_zero_post (Track *track) | |||
{ | |||
return track->zero_post.length; | |||
} | |||
void track_set_isrc (Track *track, char *isrc) | |||
{ | |||
if (track->isrc) | |||
free(track->isrc); | |||
track->isrc = strdup(isrc); | |||
} | |||
char *track_get_isrc (Track *track) | |||
{ | |||
return track->isrc; | |||
} | |||
Cdtext *track_get_cdtext (Track *track) | |||
{ | |||
return track->cdtext; | |||
} | |||
void track_add_index (Track *track, long index) | |||
{ | |||
if (MAXTRACK - 1 > track->nindex) | |||
track->nindex++; | |||
else | |||
fprintf(stderr, "too many indexes\n"); | |||
/* this will overwrite last index if there were too many */ | |||
track->index[track->nindex - 1] = index; | |||
} | |||
int track_get_nindex (Track *track) | |||
{ | |||
return track->nindex; | |||
} | |||
long track_get_index (Track *track, int i) | |||
{ | |||
if (0 <= i < track->nindex) | |||
return track->index[i]; | |||
return -1; | |||
} | |||
/* | |||
* dump cd information | |||
*/ | |||
void cd_track_dump (Track *track) | |||
{ | |||
int i; | |||
printf("zero_pre: %ld\n", track->zero_pre.length); | |||
printf("filename: %s\n", track->file.name); | |||
printf("start: %ld\n", track->file.start); | |||
printf("length: %ld\n", track->file.length); | |||
printf("zero_post: %ld\n", track->zero_post.length); | |||
printf("mode: %d\n", track->mode); | |||
printf("sub_mode: %d\n", track->sub_mode); | |||
printf("flags: 0x%x\n", track->flags); | |||
printf("isrc: %s\n", track->isrc); | |||
printf("indexes: %d\n", track->nindex); | |||
for (i = 0; i < track->nindex; ++i) | |||
printf("index %d: %ld\n", i, track->index[i]); | |||
if (NULL != track->cdtext) { | |||
printf("cdtext:\n"); | |||
/* cdtext_print(stdout, track->cdtext); */ | |||
} | |||
} | |||
void cd_dump (Cd *cd) | |||
{ | |||
int i; | |||
printf("Disc Info\n"); | |||
printf("mode: %d\n", cd->mode); | |||
printf("catalog: %s\n", cd->catalog); | |||
if (NULL != cd->cdtext) { | |||
printf("cdtext:\n"); | |||
/* cdtext_print(stdout, cd->cdtext); */ | |||
} | |||
for (i = 0; i < cd->ntrack; ++i) { | |||
printf("Track %d Info\n", i + 1); | |||
cd_track_dump(cd->track[i]); | |||
} | |||
} |
@@ -0,0 +1,147 @@ | |||
/* | |||
* cd.h -- cd structure | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
/* references: MMC-3 draft revsion - 10g */ | |||
#ifndef CD_H | |||
#define CD_H | |||
#include "cdtext.h" | |||
#define MAXTRACK 99 /* Red Book track limit */ | |||
#define MAXINDEX 99 /* Red Book index limit */ | |||
/* | |||
* disc modes | |||
* DATA FORM OF MAIN DATA (5.29.2.8) | |||
*/ | |||
enum DiscMode { | |||
MODE_CD_DA, /* CD-DA */ | |||
MODE_CD_ROM, /* CD-ROM mode 1 */ | |||
MODE_CD_ROM_XA /* CD-ROM XA and CD-I */ | |||
}; | |||
/* | |||
* track modes | |||
* 5.29.2.8 DATA FORM OF MAIN DATA | |||
* Table 350 - Data Block Type Codes | |||
*/ | |||
enum TrackMode { | |||
MODE_AUDIO, /* 2352 byte block length */ | |||
MODE_MODE1, /* 2048 byte block length */ | |||
MODE_MODE1_RAW, /* 2352 byte block length */ | |||
MODE_MODE2, /* 2336 byte block length */ | |||
MODE_MODE2_FORM1, /* 2048 byte block length */ | |||
MODE_MODE2_FORM2, /* 2324 byte block length */ | |||
MODE_MODE2_FORM_MIX, /* 2332 byte block length */ | |||
MODE_MODE2_RAW /* 2352 byte block length */ | |||
}; | |||
/* | |||
* sub-channel mode | |||
* 5.29.2.13 Data Form of Sub-channel | |||
* NOTE: not sure if this applies to cue files | |||
*/ | |||
enum TrackSubMode { | |||
SUB_MODE_RW, /* RAW Data */ | |||
SUB_MODE_RW_RAW /* PACK DATA (written R-W */ | |||
}; | |||
/* | |||
* track flags | |||
* Q Sub-channel Control Field (4.2.3.3, 5.29.2.2) | |||
*/ | |||
enum TrackFlag { | |||
FLAG_NONE =0x00, /* no flags set */ | |||
FLAG_PRE_EMPHASIS =0x01, /* audio recorded with pre-emphasis */ | |||
FLAG_COPY_PERMITTED =0x02, /* digital copy permitted */ | |||
FLAG_DATA =0x04, /* data track */ | |||
FLAG_FOUR_CHANNEL =0x08, /* 4 audio channels */ | |||
FLAG_SCMS =0x10, /* SCMS (not Q Sub-ch.) (5.29.2.7) */ | |||
FLAG_ANY =0xff /* any flags set */ | |||
}; | |||
enum DataType { | |||
DATA_AUDIO, | |||
DATA_DATA, | |||
DATA_FIFO, | |||
DATA_ZERO | |||
}; | |||
typedef struct Cd Cd; | |||
typedef struct Track Track; | |||
Cd *cd_init (); | |||
void cd_dump (Cd *cd); | |||
/* | |||
* Cd functions | |||
*/ | |||
void cd_set_mode (Cd *cd, int mode); | |||
int cd_get_mode (Cd *cd); | |||
void cd_set_catalog (Cd *cd, char *catalog); | |||
char *cd_get_catalog (Cd *cd); | |||
/* | |||
* return pointer to cd's Cdtext | |||
*/ | |||
Cdtext *cd_get_cdtext (Cd *cd); | |||
/* | |||
* add a new track to cd, increment number of tracks | |||
* and return pointer to new track | |||
*/ | |||
Track *cd_add_track (Cd *cd); | |||
/* | |||
* return number of tracks in cd | |||
*/ | |||
int cd_get_ntrack (Cd *cd); | |||
Track *cd_get_track (Cd *cd, int i); | |||
/* | |||
* Track functions | |||
*/ | |||
void track_set_filename (Track *track, char *filename); | |||
char *track_get_filename (Track *track); | |||
void track_set_start (Track *track, long start); | |||
long track_get_start (Track *track); | |||
void track_set_length (Track *track, long length); | |||
long track_get_length (Track *track); | |||
void track_set_mode (Track *track, int mode); | |||
int track_get_mode (Track *track); | |||
void track_set_sub_mode (Track *track, int sub_mode); | |||
int track_get_sub_mode (Track *track); | |||
void track_set_flag (Track *track, int flag); | |||
void track_clear_flag (Track *track, int flag); | |||
int track_is_set_flag (Track *track, int flag); | |||
void track_set_zero_pre (Track *track, long length); | |||
long track_get_zero_pre (Track *track); | |||
void track_set_zero_post (Track *track, long length); | |||
long track_get_zero_post (Track *track); | |||
void track_set_isrc (Track *track, char *isrc); | |||
char *track_get_isrc (Track *track); | |||
Cdtext *track_get_cdtext (Track *track); | |||
void track_add_index (Track *track, long index); | |||
int track_get_nindex (Track *track); | |||
long track_get_index (Track *track, int i); | |||
#endif |
@@ -0,0 +1,153 @@ | |||
/* | |||
* cdtext.c -- cdtext data structure and functions | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "cdtext.h" | |||
struct Cdtext { | |||
int pti; | |||
int format; | |||
char *value; | |||
}; | |||
Cdtext *cdtext_init () | |||
{ | |||
Cdtext *new_cdtext = NULL; | |||
Cdtext cdtext[] = { | |||
{PTI_TITLE, FORMAT_CHAR, NULL}, | |||
{PTI_PERFORMER, FORMAT_CHAR, NULL}, | |||
{PTI_SONGWRITER, FORMAT_CHAR, NULL}, | |||
{PTI_COMPOSER, FORMAT_CHAR, NULL}, | |||
{PTI_ARRANGER, FORMAT_CHAR, NULL}, | |||
{PTI_MESSAGE, FORMAT_CHAR, NULL}, | |||
{PTI_DISC_ID, FORMAT_BINARY, NULL}, | |||
{PTI_GENRE, FORMAT_BINARY, NULL}, | |||
{PTI_TOC_INFO1, FORMAT_BINARY, NULL}, | |||
{PTI_TOC_INFO2, FORMAT_BINARY, NULL}, | |||
{PTI_RESERVED1, FORMAT_CHAR, NULL}, | |||
{PTI_RESERVED2, FORMAT_CHAR, NULL}, | |||
{PTI_RESERVED3, FORMAT_CHAR, NULL}, | |||
{PTI_RESERVED4, FORMAT_CHAR, NULL}, | |||
{PTI_UPC_ISRC, FORMAT_CHAR, NULL}, | |||
{PTI_SIZE_INFO, FORMAT_BINARY, NULL}, | |||
{PTI_END, FORMAT_CHAR, NULL} | |||
}; | |||
new_cdtext = (Cdtext *) calloc (sizeof (cdtext) / sizeof (Cdtext), sizeof (Cdtext)); | |||
if (NULL == new_cdtext) | |||
fprintf (stderr, "problem allocating memory\n"); | |||
else | |||
memcpy (new_cdtext, cdtext, sizeof(cdtext)); | |||
return new_cdtext; | |||
} | |||
void cdtext_delete (Cdtext *cdtext) | |||
{ | |||
int i; | |||
if (NULL != cdtext) { | |||
for (i = 0; PTI_END != cdtext[i].pti; i++) | |||
free (cdtext[i].value); | |||
free (cdtext); | |||
} | |||
} | |||
/* return 0 if there is no cdtext, returns non-zero otherwise */ | |||
int cdtext_is_empty (Cdtext *cdtext) | |||
{ | |||
for (; PTI_END != cdtext->pti; cdtext++) | |||
if (NULL != cdtext->value) | |||
return -1; | |||
return 0; | |||
} | |||
/* sets cdtext's pti entry to field */ | |||
void cdtext_set (int pti, char *value, Cdtext *cdtext) | |||
{ | |||
if (NULL != value) /* don't pass NULL to strdup */ | |||
for (; PTI_END != cdtext->pti; cdtext++) | |||
if (pti == cdtext->pti) { | |||
free (cdtext->value); | |||
cdtext->value = strdup (value); | |||
} | |||
} | |||
/* returns value for pti, NULL if pti is not found */ | |||
char *cdtext_get (int pti, Cdtext *cdtext) | |||
{ | |||
for (; PTI_END != cdtext->pti; cdtext++) | |||
if (pti == cdtext->pti) | |||
return cdtext->value; | |||
return NULL; | |||
} | |||
const char *cdtext_get_key (int pti, int istrack) | |||
{ | |||
char *key = NULL; | |||
switch (pti) { | |||
case PTI_TITLE: | |||
key = "TITLE"; | |||
break; | |||
case PTI_PERFORMER: | |||
key = "PERFORMER"; | |||
break; | |||
case PTI_SONGWRITER: | |||
key = "SONGWRITER"; | |||
break; | |||
case PTI_COMPOSER: | |||
key = "COMPOSER"; | |||
break; | |||
case PTI_ARRANGER: | |||
key = "ARRANGER"; | |||
break; | |||
case PTI_MESSAGE: | |||
key = "MESSAGE"; | |||
break; | |||
case PTI_DISC_ID: | |||
key = "DISC_ID"; | |||
break; | |||
case PTI_GENRE: | |||
key = "GENRE"; | |||
break; | |||
case PTI_TOC_INFO1: | |||
key = "TOC_INFO1"; | |||
break; | |||
case PTI_TOC_INFO2: | |||
key = "TOC_INFO1"; | |||
break; | |||
case PTI_RESERVED1: | |||
/* reserved */ | |||
break; | |||
case PTI_RESERVED2: | |||
/* reserved */ | |||
break; | |||
case PTI_RESERVED3: | |||
/* reserved */ | |||
break; | |||
case PTI_RESERVED4: | |||
/* reserved */ | |||
break; | |||
case PTI_UPC_ISRC: | |||
if (0 == istrack) | |||
key = "UPC_EAN"; | |||
else | |||
key = "ISRC"; | |||
break; | |||
case PTI_SIZE_INFO: | |||
key = "SIZE_INFO"; | |||
break; | |||
} | |||
return key; | |||
} |
@@ -0,0 +1,65 @@ | |||
/* | |||
* cdtext.h | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
/* references: MMC-3 draft revsion - 10g */ | |||
#ifndef CDTEXT_H | |||
#define CDTEXT_H | |||
#include <stdio.h> | |||
/* cdtext pack type indicators */ | |||
enum Pti { | |||
PTI_TITLE, /* title of album or track titles */ | |||
PTI_PERFORMER, /* name(s) of the performer(s) */ | |||
PTI_SONGWRITER, /* name(s) of the songwriter(s) */ | |||
PTI_COMPOSER, /* name(s) of the composer(s) */ | |||
PTI_ARRANGER, /* name(s) of the arranger(s) */ | |||
PTI_MESSAGE, /* message(s) from the content provider and/or artist */ | |||
PTI_DISC_ID, /* (binary) disc identification information */ | |||
PTI_GENRE, /* (binary) genre identification and genre information */ | |||
PTI_TOC_INFO1, /* (binary) table of contents information */ | |||
PTI_TOC_INFO2, /* (binary) second table of contents information */ | |||
PTI_RESERVED1, /* reserved */ | |||
PTI_RESERVED2, /* reserved */ | |||
PTI_RESERVED3, /* reserved */ | |||
PTI_RESERVED4, /* reserved for content provider only */ | |||
PTI_UPC_ISRC, /* UPC/EAN code of the album and ISRC code of each track */ | |||
PTI_SIZE_INFO, /* (binary) size information of the block */ | |||
PTI_END /* terminating PTI (for stepping through PTIs) */ | |||
}; | |||
enum PtiFormat { | |||
FORMAT_CHAR, /* single or double byte character string */ | |||
FORMAT_BINARY /* binary data */ | |||
}; | |||
typedef struct Cdtext Cdtext; | |||
/* return a pointer to a new Cdtext */ | |||
Cdtext *cdtext_init (); | |||
/* release a Cdtext */ | |||
void cdtext_delete (Cdtext *cdtext); | |||
/* returns non-zero if there are no CD-TEXT fields set, zero otherwise */ | |||
int cdtext_is_empty (Cdtext *cdtext); | |||
/* set CD-TEXT field to value for PTI pti */ | |||
void cdtext_set (int pti, char *value, Cdtext *cdtext); | |||
/* returns pointer to CD-TEXT value for PTI pti */ | |||
char *cdtext_get (int pti, Cdtext *cdtext); | |||
/* | |||
* returns appropriate string for PTI pti | |||
* if istrack is zero, UPC/EAN string will be returned for PTI_UPC_ISRC | |||
* othwise ISRC string will be returned | |||
*/ | |||
const char *cdtext_get_key (int pti, int istrack); | |||
#endif |
@@ -0,0 +1,6 @@ | |||
/* | |||
* cue.h -- cue function declarations | |||
*/ | |||
Cd *cue_parse (FILE *fp); | |||
void cue_print (FILE *fp, Cd *cd); |
@@ -0,0 +1,277 @@ | |||
%{ | |||
/* | |||
* cue_parse.y -- parser for cue files | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
#include "time.h" | |||
#define YYDEBUG 1 | |||
extern int cue_yylex(); | |||
void yyerror (char *s); | |||
static Cd *cd = NULL; | |||
static Track *track = NULL; | |||
static Track *prev_track = NULL; | |||
static Cdtext *cdtext = NULL; | |||
static char *prev_filename = NULL; /* last file in or before last track */ | |||
static char *cur_filename = NULL; /* last file in the last track */ | |||
static char *new_filename = NULL; /* last file in this track */ | |||
%} | |||
%start cuefile | |||
%union { | |||
long ival; | |||
char *sval; | |||
} | |||
%token <ival> NUMBER | |||
%token <sval> STRING | |||
/* global (header) */ | |||
%token CATALOG | |||
%token FFILE | |||
%token BINARY | |||
%token MOTOROLA | |||
%token AIFF | |||
%token WAVE | |||
%token MP3 | |||
/* track */ | |||
%token TRACK | |||
%token <ival> AUDIO | |||
%token <ival> MODE1_2048 | |||
%token <ival> MODE1_2352 | |||
%token <ival> MODE2_2336 | |||
%token <ival> MODE2_2048 | |||
%token <ival> MODE2_2342 | |||
%token <ival> MODE2_2332 | |||
%token <ival> MODE2_2352 | |||
/* ISRC is with CD_TEXT */ | |||
%token TRACK_ISRC | |||
%token FLAGS | |||
%token <ival> PRE | |||
%token <ival> DCP | |||
%token <ival> FOUR_CH | |||
%token <ival> SCMS | |||
%token PREGAP | |||
%token INDEX | |||
%token POSTGAP | |||
/* CD-TEXT */ | |||
%token <ival> TITLE | |||
%token <ival> PERFORMER | |||
%token <ival> SONGWRITER | |||
%token <ival> COMPOSER | |||
%token <ival> ARRANGER | |||
%token <ival> MESSAGE | |||
%token <ival> DISC_ID | |||
%token <ival> GENRE | |||
%token <ival> TOC_INFO1 | |||
%token <ival> TOC_INFO2 | |||
%token <ival> UPC_EAN | |||
%token <ival> ISRC | |||
%token <ival> SIZE_INFO | |||
%type <ival> track_mode | |||
%type <ival> track_flag | |||
%type <ival> time | |||
%type <ival> cdtext_item | |||
%% | |||
cuefile | |||
: new_cd global_statements track_list | |||
; | |||
new_cd | |||
: /* empty */ { | |||
cd = cd_init(); | |||
cdtext = cd_get_cdtext(cd); | |||
} | |||
; | |||
global_statements | |||
: /* empty */ | |||
| global_statements global_statement | |||
; | |||
global_statement | |||
: CATALOG STRING '\n' { cd_set_catalog(cd, $2); } | |||
| cdtext | |||
| track_data | |||
| error '\n' | |||
; | |||
track_data | |||
: FFILE STRING file_format '\n' { | |||
if (NULL != new_filename) { | |||
yyerror("too many files specified\n"); | |||
free(new_filename); | |||
} | |||
new_filename = strdup($2); | |||
} | |||
; | |||
track_list | |||
: track | |||
| track_list track | |||
; | |||
track | |||
: new_track track_def track_statements | |||
; | |||
file_format | |||
: BINARY | |||
| MOTOROLA | |||
| AIFF | |||
| WAVE | |||
| MP3 | |||
; | |||
new_track | |||
: /*empty */ { | |||
/* save previous track, to later set length */ | |||
prev_track = track; | |||
track = cd_add_track(cd); | |||
cdtext = track_get_cdtext(track); | |||
cur_filename = new_filename; | |||
if (NULL != cur_filename) | |||
prev_filename = cur_filename; | |||
if (NULL == prev_filename) | |||
yyerror("no file specified for track"); | |||
else | |||
track_set_filename(track, prev_filename); | |||
new_filename = NULL; | |||
} | |||
; | |||
track_def | |||
: TRACK NUMBER track_mode '\n' { | |||
track_set_mode(track, $3); | |||
} | |||
; | |||
track_mode | |||
: AUDIO | |||
| MODE1_2048 | |||
| MODE1_2352 | |||
| MODE2_2336 | |||
| MODE2_2048 | |||
| MODE2_2342 | |||
| MODE2_2332 | |||
| MODE2_2352 | |||
; | |||
track_statements | |||
: track_statement | |||
| track_statements track_statement | |||
; | |||
track_statement | |||
: cdtext | |||
| FLAGS track_flags '\n' | |||
| TRACK_ISRC STRING '\n' { track_set_isrc(track, $2); } | |||
| PREGAP time '\n' { track_set_zero_pre(track, $2); } | |||
| INDEX NUMBER time '\n' { | |||
int i = track_get_nindex(track); | |||
long prev_length; | |||
if (0 == i) { | |||
/* first index */ | |||
track_set_start(track, $3); | |||
if (NULL != prev_track && NULL == cur_filename) { | |||
/* track shares file with previous track */ | |||
prev_length = $3 - track_get_start(prev_track); | |||
track_set_length(prev_track, prev_length); | |||
} | |||
} | |||
for (; i <= $2; i++) | |||
track_add_index(track, \ | |||
track_get_zero_pre(track) + $3 \ | |||
- track_get_start(track)); | |||
} | |||
| POSTGAP time '\n' { track_set_zero_post(track, $2); } | |||
| track_data | |||
| error '\n' | |||
; | |||
track_flags | |||
: /* empty */ | |||
| track_flags track_flag { track_set_flag(track, $2); } | |||
; | |||
track_flag | |||
: PRE | |||
| DCP | |||
| FOUR_CH | |||
| SCMS | |||
; | |||
cdtext | |||
: cdtext_item STRING '\n' { cdtext_set ($1, $2, cdtext); } | |||
; | |||
cdtext_item | |||
: TITLE | |||
| PERFORMER | |||
| SONGWRITER | |||
| COMPOSER | |||
| ARRANGER | |||
| MESSAGE | |||
| DISC_ID | |||
| GENRE | |||
| TOC_INFO1 | |||
| TOC_INFO2 | |||
| UPC_EAN | |||
| ISRC | |||
| SIZE_INFO | |||
; | |||
time | |||
: NUMBER | |||
| NUMBER ':' NUMBER ':' NUMBER { $$ = time_msf_to_frame($1, $3, $5); } | |||
; | |||
%% | |||
/* lexer interface */ | |||
extern int cue_lineno; | |||
extern int cue_yydebug; | |||
extern FILE *cue_yyin; | |||
void yyerror (char *s) | |||
{ | |||
fprintf(stderr, "%d: %s\n", cue_lineno, s); | |||
} | |||
Cd *cue_parse (FILE *fp) | |||
{ | |||
cue_yyin = fp; | |||
cue_yydebug = 0; | |||
if (0 == cue_yyparse()) | |||
return cd; | |||
return NULL; | |||
} |
@@ -0,0 +1,146 @@ | |||
/* | |||
* cue_print.y -- print cue file | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
#include "time.h" | |||
void cue_print_track (FILE *fp, Track *track, int trackno); | |||
void cue_print_cdtext (Cdtext *cdtext, FILE *fp, int istrack); | |||
void cue_print_index (long i, FILE *fp); | |||
char *filename = ""; /* last track datafile */ | |||
long prev_length = 0; /* last track length */ | |||
/* prints cd in cue format */ | |||
void cue_print (FILE *fp, Cd *cd) | |||
{ | |||
Cdtext *cdtext = cd_get_cdtext(cd); | |||
int i; /* track */ | |||
Track *track = NULL; | |||
/* print global information */ | |||
if (NULL != cd_get_catalog(cd)) | |||
fprintf(fp, "CATALOG %s\n", cd_get_catalog(cd)); | |||
cue_print_cdtext(cdtext, fp, 0); | |||
/* print track information */ | |||
for (i = 1; i <= cd_get_ntrack(cd); i++) { | |||
track = cd_get_track(cd, i); | |||
fprintf(fp, "\n"); | |||
cue_print_track(fp, track, i); | |||
} | |||
} | |||
void cue_print_track (FILE *fp, Track *track, int trackno) | |||
{ | |||
Cdtext *cdtext = track_get_cdtext(track); | |||
int i; /* index */ | |||
if (NULL != track_get_filename(track)) { | |||
/* | |||
* always print filename for track 1, afterwards only | |||
* print filename if it differs from the previous track | |||
*/ | |||
if (0 != strcmp(track_get_filename(track), filename)) { | |||
filename = track_get_filename(track); | |||
fprintf(fp, "FILE \"%s\" ", filename); | |||
/* NOTE: what to do with other formats (MP3, etc)? */ | |||
if (MODE_AUDIO == track_get_mode(track)) | |||
fprintf(fp, "WAVE\n"); | |||
else | |||
fprintf(fp, "BINARY\n"); | |||
} | |||
} | |||
fprintf(fp, "TRACK %02d ", trackno); | |||
switch (track_get_mode(track)) { | |||
case MODE_AUDIO: | |||
fprintf(fp, "AUDIO\n"); | |||
break; | |||
case MODE_MODE1: | |||
fprintf(fp, "MODE1/2048\n"); | |||
break; | |||
case MODE_MODE1_RAW: | |||
fprintf(fp, "MODE1/2352\n"); | |||
break; | |||
case MODE_MODE2: | |||
fprintf(fp, "MODE2/2048\n"); | |||
break; | |||
case MODE_MODE2_FORM1: | |||
fprintf(fp, "MODE2/2336\n"); | |||
break; | |||
case MODE_MODE2_FORM2: | |||
fprintf(fp, "MODE2/2324\n"); | |||
break; | |||
case MODE_MODE2_FORM_MIX: | |||
fprintf(fp, "MODE2/2336\n"); | |||
break; | |||
case MODE_MODE2_RAW: | |||
fprintf(fp, "MODE2/2352\n"); | |||
break; | |||
} | |||
cue_print_cdtext(cdtext, fp, 1); | |||
if (0 != track_is_set_flag(track, FLAG_ANY)) { | |||
fprintf(fp, "FLAGS"); | |||
if (0 != track_is_set_flag(track, FLAG_PRE_EMPHASIS)) | |||
fprintf(fp, " PRE"); | |||
if (0 != track_is_set_flag(track, FLAG_COPY_PERMITTED)) | |||
fprintf(fp, " DCP"); | |||
if (0 != track_is_set_flag(track, FLAG_FOUR_CHANNEL)) | |||
fprintf(fp, " 4CH"); | |||
if (0 != track_is_set_flag(track, FLAG_SCMS)) | |||
fprintf(fp, " SCMS"); | |||
fprintf(fp, "\n"); | |||
} | |||
if (NULL != track_get_isrc(track)) | |||
fprintf(fp, "ISRC %s\n", track_get_isrc(track)); | |||
if (0 != track_get_zero_pre(track)) | |||
fprintf (fp, "PREGAP %s\n", time_frame_to_mmssff(track_get_zero_pre(track))); | |||
/* don't print index 0 if index 1 = 0 */ | |||
if (track_get_index(track, 1) == 0) | |||
i = 1; | |||
else | |||
i = 0; | |||
for (; i < track_get_nindex(track); i++) { | |||
fprintf(fp, "INDEX %02d ", i); | |||
cue_print_index( \ | |||
track_get_index(track, i) \ | |||
+ track_get_start(track) \ | |||
- track_get_zero_pre(track) , fp); | |||
} | |||
if (0 != track_get_zero_post(track)) | |||
fprintf (fp, "POSTGAP %s\n", time_frame_to_mmssff(track_get_zero_post(track))); | |||
prev_length = track_get_length(track); | |||
} | |||
void cue_print_cdtext (Cdtext *cdtext, FILE *fp, int istrack) | |||
{ | |||
int pti; | |||
char *value = NULL; | |||
for (pti = 0; PTI_END != pti; pti++) | |||
if (NULL != (value = cdtext_get(pti, cdtext))) { | |||
fprintf(fp, "%s", cdtext_get_key(pti, istrack)); | |||
fprintf(fp, " \"%s\"\n", value); | |||
} | |||
} | |||
void cue_print_index (long i, FILE *fp) | |||
{ | |||
fprintf (fp, "%s\n", time_frame_to_mmssff(i)); | |||
} |
@@ -0,0 +1,94 @@ | |||
%{ | |||
/* | |||
* cue_scan.l -- lexer for cue files | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
#include "cue_parse.h" | |||
int cue_lineno = 1; | |||
%} | |||
ws [ \t\r] | |||
nonws [^ \t\r\n] | |||
%option noyywrap | |||
%s NAME | |||
%% | |||
\"(\\.|[^\\"])*\" { | |||
cue_yylval.sval = strdup(yytext + 1); | |||
cue_yylval.sval[strlen(cue_yylval.sval) - 1] = '\0'; | |||
BEGIN(INITIAL); | |||
return STRING; | |||
} | |||
<NAME>{nonws}+ { | |||
cue_yylval.sval = strdup(yytext); | |||
BEGIN(INITIAL); | |||
return STRING; | |||
} | |||
CATALOG { BEGIN(NAME); return CATALOG; } | |||
FILE { BEGIN(NAME); return FFILE; } | |||
BINARY { return BINARY; } | |||
MOTOROLA { return MOTOROLA; } | |||
AIFF { return AIFF; } | |||
WAVE { return WAVE; } | |||
MP3 { return MP3; } | |||
TRACK { return TRACK; } | |||
AUDIO { cue_yylval.ival = MODE_AUDIO; return AUDIO; } | |||
MODE1\/2048 { cue_yylval.ival = MODE_MODE1; return MODE1_2048; } | |||
MODE1\/2352 { cue_yylval.ival = MODE_MODE1_RAW; return MODE1_2352; } | |||
MODE2\/2336 { cue_yylval.ival = MODE_MODE2; return MODE2_2336; } | |||
MODE2\/2048 { cue_yylval.ival = MODE_MODE2_FORM1; return MODE2_2048; } | |||
MODE2\/2342 { cue_yylval.ival = MODE_MODE2_FORM2; return MODE2_2342; } | |||
MODE2\/2332 { cue_yylval.ival = MODE_MODE2_FORM_MIX; return MODE2_2332; } | |||
MODE2\/2352 { cue_yylval.ival = MODE_MODE2_RAW; return MODE2_2352; } | |||
FLAGS { return FLAGS; } | |||
PRE { cue_yylval.ival = FLAG_PRE_EMPHASIS; return PRE; } | |||
DCP { cue_yylval.ival = FLAG_COPY_PERMITTED; return DCP; } | |||
4CH { cue_yylval.ival = FLAG_FOUR_CHANNEL; return FOUR_CH; } | |||
SCMS { cue_yylval.ival = FLAG_SCMS; return SCMS; } | |||
PREGAP { return PREGAP; } | |||
INDEX { return INDEX; } | |||
POSTGAP { return POSTGAP; } | |||
TITLE { BEGIN(NAME); cue_yylval.ival = PTI_TITLE; return TITLE; } | |||
PERFORMER { BEGIN(NAME); cue_yylval.ival = PTI_PERFORMER; return PERFORMER; } | |||
SONGWRITER { BEGIN(NAME); cue_yylval.ival = PTI_SONGWRITER; return SONGWRITER; } | |||
COMPOSER { BEGIN(NAME); cue_yylval.ival = PTI_COMPOSER; return COMPOSER; } | |||
ARRANGER { BEGIN(NAME); cue_yylval.ival = PTI_ARRANGER; return ARRANGER; } | |||
MESSAGE { BEGIN(NAME); cue_yylval.ival = PTI_MESSAGE; return MESSAGE; } | |||
DISC_ID { BEGIN(NAME); cue_yylval.ival = PTI_DISC_ID; return DISC_ID; } | |||
GENRE { BEGIN(NAME); cue_yylval.ival = PTI_GENRE; return GENRE; } | |||
TOC_INFO1 { BEGIN(NAME); cue_yylval.ival = PTI_TOC_INFO1; return TOC_INFO1; } | |||
TOC_INFO2 { BEGIN(NAME); cue_yylval.ival = PTI_TOC_INFO2; return TOC_INFO2; } | |||
UPC_EAN { BEGIN(NAME); cue_yylval.ival = PTI_UPC_ISRC; return UPC_EAN; } | |||
ISRC/{ws}+\" { BEGIN(NAME); cue_yylval.ival = PTI_UPC_ISRC; return ISRC; } | |||
SIZE_INFO { BEGIN(NAME); cue_yylval.ival = PTI_SIZE_INFO; return SIZE_INFO; } | |||
ISRC { BEGIN(NAME); return TRACK_ISRC; } | |||
^{ws}*REM.*\n { cue_lineno++; /* ignore comments */ } | |||
{ws}+ { /* ignore whitespace */ } | |||
[[:digit:]]+ { cue_yylval.ival = atoi(yytext); return NUMBER; } | |||
: { return yytext[0]; } | |||
^{ws}*\n { cue_lineno++; /* blank line */ } | |||
\n { cue_lineno++; return '\n'; } | |||
. { fprintf(stderr, "bad character '%c'\n", yytext[0]); } | |||
%% |
@@ -0,0 +1,90 @@ | |||
/* | |||
* cuefile.c -- cue/toc functions | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "cuefile.h" | |||
#include "cue.h" | |||
#include "toc.h" | |||
Cd *cf_parse (char *name, int *format) | |||
{ | |||
FILE *fp = NULL; | |||
Cd *cd = NULL; | |||
if (UNKNOWN == *format) | |||
if (UNKNOWN == (*format = cf_format_from_suffix(name))) { | |||
fprintf(stderr, "%s: unknown format\n", name); | |||
return NULL; | |||
} | |||
if (0 == strcmp("-", name)) { | |||
fp = stdin; | |||
} else if (NULL == (fp = fopen(name, "r"))) { | |||
fprintf(stderr, "%s: error opening file\n", name); | |||
return NULL; | |||
} | |||
switch (*format) { | |||
case CUE: | |||
cd = cue_parse(fp); | |||
break; | |||
case TOC: | |||
cd = toc_parse(fp); | |||
break; | |||
} | |||
if(stdin != fp) | |||
fclose(fp); | |||
return cd; | |||
} | |||
int cf_print (char *name, int *format, Cd *cd) | |||
{ | |||
FILE *fp = NULL; | |||
if (UNKNOWN == *format) | |||
if (UNKNOWN == (*format = cf_format_from_suffix(name))) { | |||
fprintf(stderr, "%s: unknown format\n", name); | |||
return -1; | |||
} | |||
if (0 == strcmp("-", name)) { | |||
fp = stdout; | |||
} else if (NULL == (fp = fopen(name, "w"))) { | |||
fprintf(stderr, "%s: error opening file\n", name); | |||
return -1; | |||
} | |||
switch (*format) { | |||
case CUE: | |||
cue_print(fp, cd); | |||
break; | |||
case TOC: | |||
toc_print(fp, cd); | |||
break; | |||
} | |||
if(stdout != fp) | |||
fclose(fp); | |||
return 0; | |||
} | |||
int cf_format_from_suffix (char *name) | |||
{ | |||
char *suffix; | |||
if (0 != (suffix = strrchr(name, '.'))) { | |||
if (0 == strcasecmp(".cue", suffix)) | |||
return CUE; | |||
else if (0 == strcasecmp(".toc", suffix)) | |||
return TOC; | |||
} | |||
return UNKNOWN; | |||
} |
@@ -0,0 +1,16 @@ | |||
/* | |||
* cuefile.h -- cue/toc public declarations | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include "cd.h" | |||
enum {CUE, TOC, UNKNOWN}; | |||
typedef struct Cue Cue; | |||
Cd *cf_parse (char *fname, int *format); | |||
int cf_print (char *fname, int *format, Cd *cue); | |||
int cf_format_from_suffix (char *fname); |
@@ -0,0 +1,43 @@ | |||
/* | |||
* time.c -- time functions | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
long time_msf_to_frame (int m, int s, int f) | |||
{ | |||
return (m * 60 + s) * 75 + f; | |||
} | |||
void msf_frame_to_msf (long frame, int *m, int *s, int *f) | |||
{ | |||
*f = frame % 75; /* 0 <= frames <= 74 */ | |||
frame /= 75; | |||
*s = frame % 60; /* 0 <= seconds <= 59 */ | |||
frame /= 60; | |||
*m = frame; /* 0 <= minutes */ | |||
} | |||
void time_frame_to_msf (long frame, int *m, int *s, int *f) | |||
{ | |||
*f = frame % 75; /* 0 <= frames <= 74 */ | |||
frame /= 75; | |||
*s = frame % 60; /* 0 <= seconds <= 59 */ | |||
frame /= 60; | |||
*m = frame; /* 0 <= minutes */ | |||
} | |||
/* print frame in mm:ss:ff format */ | |||
char *time_frame_to_mmssff (long f) | |||
{ | |||
static char msf[9]; | |||
int minutes, seconds, frames; | |||
msf_frame_to_msf(f, &minutes, &seconds, &frames); | |||
sprintf(msf, "%02d:%02d:%02d", minutes, seconds, frames); | |||
return msf; | |||
} |
@@ -0,0 +1,15 @@ | |||
/* time.h -- time declarations | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#ifndef TIME_H | |||
#define TIME_H | |||
long time_msf_to_frame (int m, int s, int f); | |||
long time_mmssff_to_frame (char *mmssff); | |||
void time_frame_to_msf (long frame, int *m, int *s, int *f); | |||
char *time_frame_to_mmssff (long f); | |||
#endif |
@@ -0,0 +1,6 @@ | |||
/* | |||
* toc.h -- toc function declarations | |||
*/ | |||
Cd *toc_parse (FILE *fp); | |||
void toc_print (FILE *fp, Cd *cd); |
@@ -0,0 +1,345 @@ | |||
%{ | |||
/* | |||
* toc_parse.y -- parser for toc files | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
#include "time.h" | |||
#define YYDEBUG 1 | |||
extern int toc_yylex(); | |||
void yyerror (char *s); | |||
static Cd *cd = NULL; | |||
static Track *track = NULL; | |||
static Cdtext *cdtext = NULL; | |||
%} | |||
%start tocfile | |||
%union { | |||
long ival; | |||
char *sval; | |||
} | |||
%token <ival> NUMBER | |||
%token <sval> STRING | |||
/* global (header) */ | |||
%token CATALOG | |||
%token <ival> CD_DA | |||
%token <ival> CD_ROM | |||
%token <ival> CD_ROM_XA | |||
/* track */ | |||
%token TRACK | |||
%token <ival> AUDIO | |||
%token <ival> MODE1 | |||
%token <ival> MODE1_RAW | |||
%token <ival> MODE2 | |||
%token <ival> MODE2_FORM1 | |||
%token <ival> MODE2_FORM2 | |||
%token <ival> MODE2_FORM_MIX | |||
%token <ival> MODE2_RAW | |||
%token <ival> RW | |||
%token <ival> RW_RAW | |||
%token NO | |||
%token <ival> COPY | |||
%token <ival> PRE_EMPHASIS | |||
%token <ival> TWO_CHANNEL_AUDIO | |||
%token <ival> FOUR_CHANNEL_AUDIO | |||
%token ISRC | |||
%token SILENCE | |||
%token ZERO | |||
%token AUDIOFILE | |||
%token DATAFILE | |||
%token FIFO | |||
%token START | |||
%token PREGAP | |||
%token INDEX | |||
/* CD-TEXT */ | |||
%token CD_TEXT | |||
%token LANGUAGE_MAP | |||
%token LANGUAGE | |||
%token <ival> TITLE | |||
%token <ival> PERFORMER | |||
%token <ival> SONGWRITER | |||
%token <ival> COMPOSER | |||
%token <ival> ARRANGER | |||
%token <ival> MESSAGE | |||
%token <ival> DISC_ID | |||
%token <ival> GENRE | |||
%token <ival> TOC_INFO1 | |||
%token <ival> TOC_INFO2 | |||
%token <ival> UPC_EAN | |||
%token <ival> ISRC | |||
%token <ival> SIZE_INFO | |||
%type <ival> disc_mode | |||
%type <ival> track_modes | |||
%type <ival> track_mode | |||
%type <ival> track_sub_mode | |||
%type <ival> track_set_flag | |||
%type <ival> track_clear_flag | |||
%type <ival> time | |||
%type <ival> cdtext_item | |||
%% | |||
tocfile | |||
: new_cd global_statements track_list | |||
; | |||
new_cd | |||
: /* empty */ { | |||
cd = cd_init(); | |||
cdtext = cd_get_cdtext(cd); | |||
} | |||
; | |||
global_statements | |||
: /* empty */ | |||
| global_statements global_statement | |||
; | |||
global_statement | |||
: CATALOG STRING '\n' { cd_set_catalog(cd, $2); } | |||
| disc_mode '\n' { cd_set_mode(cd, $1); } | |||
| CD_TEXT '{' opt_nl language_map cdtext_langs '}' '\n' | |||
| error '\n' | |||
; | |||
disc_mode | |||
: CD_DA | |||
| CD_ROM | |||
| CD_ROM_XA | |||
; | |||
track_list | |||
: track | |||
| track_list track | |||
; | |||
track | |||
: new_track track_def track_statements { | |||
while (2 > track_get_nindex(track)) | |||
track_add_index(track, 0); | |||
} | |||
; | |||
new_track | |||
: /* empty */ { | |||
track = cd_add_track(cd); | |||
cdtext = track_get_cdtext(track); | |||
/* add 0 index */ | |||
track_add_index(track, 0); | |||
} | |||
; | |||
track_def | |||
: TRACK track_modes '\n' { track_set_mode(track, $2); } | |||
; | |||
track_modes | |||
: track_mode | |||
| track_mode track_sub_mode { track_set_sub_mode(track, $2); } | |||
; | |||
track_mode | |||
: AUDIO | |||
| MODE1 | |||
| MODE1_RAW | |||
| MODE2 | |||
| MODE2_FORM1 | |||
| MODE2_FORM2 | |||
| MODE2_FORM_MIX | |||
| MODE2_RAW | |||
; | |||
track_sub_mode | |||
: RW | |||
| RW_RAW | |||
; | |||
track_statements | |||
: track_statement | |||
| track_statements track_statement | |||
; | |||
track_statement | |||
: track_flags | |||
| ISRC STRING '\n' { track_set_isrc(track, $2); } | |||
| CD_TEXT '{' opt_nl cdtext_langs '}' '\n' | |||
| track_data | |||
| track_pregap | |||
| track_index | |||
| error '\n' | |||
; | |||
track_flags | |||
: track_set_flag { track_set_flag(track, $1); } | |||
| track_clear_flag { track_clear_flag(track, $1); } | |||
; | |||
track_set_flag | |||
: COPY '\n' | |||
| PRE_EMPHASIS '\n' | |||
| FOUR_CHANNEL_AUDIO '\n' | |||
; | |||
track_clear_flag | |||
: NO PRE_EMPHASIS '\n' { $$ = $2; } | |||
| NO COPY '\n' { $$ = $2; } | |||
| TWO_CHANNEL_AUDIO '\n' | |||
; | |||
track_data | |||
: zero_data time '\n' { | |||
if (NULL == track_get_filename(track)) | |||
track_set_zero_pre(track, $2); | |||
else | |||
track_set_zero_post(track, $2); | |||
} | |||
| AUDIOFILE STRING time '\n' { | |||
track_set_filename(track, $2); | |||
track_set_start(track, $3); | |||
} | |||
| AUDIOFILE STRING time time '\n' { | |||
track_set_filename(track, $2); | |||
track_set_start(track, $3); | |||
track_set_length(track, $4); | |||
} | |||
| DATAFILE STRING '\n' { | |||
track_set_filename(track, $2); | |||
} | |||
| DATAFILE STRING time '\n' { | |||
track_set_filename(track, $2); | |||
track_set_start(track, $3); | |||
} | |||
| FIFO STRING time '\n' { | |||
track_set_filename(track, $2); | |||
track_set_start(track, $3); | |||
} | |||
; | |||
zero_data | |||
: SILENCE | |||
| ZERO | |||
; | |||
track_pregap | |||
: START '\n' | |||
| START time '\n' { | |||
track_add_index(track, $2); | |||
} | |||
| PREGAP time '\n' { | |||
track_set_zero_pre(track, $2); | |||
track_add_index(track, $2); | |||
} | |||
; | |||
track_index | |||
: INDEX time '\n' { track_add_index(track, $2); } | |||
; | |||
language_map | |||
: LANGUAGE_MAP '{' opt_nl languages '}' '\n' | |||
; | |||
languages | |||
: language | |||
| languages language | |||
; | |||
language | |||
: NUMBER ':' NUMBER opt_nl | |||
; | |||
cdtext_langs | |||
: cdtext_lang | |||
| cdtext_langs cdtext_lang | |||
; | |||
cdtext_lang | |||
: LANGUAGE NUMBER '{' opt_nl cdtext_defs '}' '\n' | |||
; | |||
cdtext_defs | |||
: /* empty */ | |||
| cdtext_defs cdtext_def | |||
; | |||
cdtext_def | |||
: cdtext_item STRING '\n' { | |||
cdtext_set ($1, $2, cdtext); | |||
} | |||
| cdtext_item '{' bytes '}' '\n' { | |||
yyerror("binary CD-TEXT data not supported\n"); | |||
} | |||
; | |||
cdtext_item | |||
: TITLE | |||
| PERFORMER | |||
| SONGWRITER | |||
| COMPOSER | |||
| ARRANGER | |||
| MESSAGE | |||
| DISC_ID | |||
| GENRE | |||
| TOC_INFO1 | |||
| TOC_INFO2 | |||
| UPC_EAN | |||
| ISRC | |||
| SIZE_INFO | |||
; | |||
bytes | |||
: /* empty */ | |||
| bytes ',' NUMBER | |||
; | |||
time | |||
: NUMBER { $$ = $1; } | |||
| NUMBER ':' NUMBER ':' NUMBER { $$ = time_msf_to_frame($1, $3, $5); } | |||
; | |||
opt_nl | |||
: /* empty */ | |||
| '\n' | |||
; | |||
%% | |||
/* lexer interface */ | |||
extern int toc_lineno; | |||
extern int toc_yydebug; | |||
extern FILE *toc_yyin; | |||
void yyerror (char *s) | |||
{ | |||
fprintf(stderr, "%d: %s\n", toc_lineno, s); | |||
} | |||
Cd *toc_parse (FILE *fp) | |||
{ | |||
toc_yyin = fp; | |||
toc_yydebug = 0; | |||
if (0 == toc_yyparse()) | |||
return cd; | |||
return NULL; | |||
} |
@@ -0,0 +1,149 @@ | |||
/* | |||
* toc_print.c -- print toc file | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
#include "time.h" | |||
void toc_print_track (FILE *fp, Track *track); | |||
void toc_print_cdtext (Cdtext *cdtext, FILE *fp, int istrack); | |||
void toc_print (FILE *fp, Cd *cd) | |||
{ | |||
Cdtext *cdtext = cd_get_cdtext(cd); | |||
int i; /* track */ | |||
Track *track; | |||
switch(cd_get_mode(cd)) { | |||
case MODE_CD_DA: | |||
fprintf(fp, "CD_DA\n"); | |||
break; | |||
case MODE_CD_ROM: | |||
fprintf(fp, "CD_ROM\n"); | |||
break; | |||
case MODE_CD_ROM_XA: | |||
fprintf(fp, "CD_ROM_XA\n"); | |||
break; | |||
} | |||
if (NULL != cd_get_catalog(cd)) | |||
fprintf(fp, "CATALOG \"%s\"\n", cd_get_catalog(cd)); | |||
if(0 != cdtext_is_empty(cdtext)) { | |||
fprintf(fp, "CD_TEXT {\n"); | |||
fprintf(fp, "\tLANGUAGE_MAP { 0:9 }\n"); | |||
fprintf(fp, "\tLANGUAGE 0 {\n"); | |||
toc_print_cdtext(cdtext, fp, 0); | |||
fprintf(fp, "\t}\n"); | |||
fprintf(fp, "}\n"); | |||
} | |||
for (i = 1; i <= cd_get_ntrack(cd); i++) { | |||
track = cd_get_track(cd, i); | |||
fprintf(fp, "\n"); | |||
toc_print_track(fp, track); | |||
} | |||
} | |||
void toc_print_track (FILE *fp, Track *track) | |||
{ | |||
Cdtext *cdtext = track_get_cdtext(track); | |||
int i; /* index */ | |||
fprintf(fp, "TRACK "); | |||
switch (track_get_mode(track)) { | |||
case MODE_AUDIO: | |||
fprintf(fp, "AUDIO"); | |||
break; | |||
case MODE_MODE1: | |||
fprintf(fp, "MODE1"); | |||
break; | |||
case MODE_MODE1_RAW: | |||
fprintf(fp, "MODE1_RAW"); | |||
break; | |||
case MODE_MODE2: | |||
fprintf(fp, "MODE2"); | |||
break; | |||
case MODE_MODE2_FORM1: | |||
fprintf(fp, "MODE2_FORM1"); | |||
break; | |||
case MODE_MODE2_FORM2: | |||
fprintf(fp, "MODE2_FORM2"); | |||
break; | |||
case MODE_MODE2_FORM_MIX: | |||
fprintf(fp, "MODE2_FORM_MIX"); | |||
break; | |||
} | |||
fprintf(fp, "\n"); | |||
if (0 != track_is_set_flag(track, FLAG_PRE_EMPHASIS)) | |||
fprintf(fp, "PRE_EMPHASIS\n"); | |||
if (0 != track_is_set_flag(track, FLAG_COPY_PERMITTED)) | |||
fprintf(fp, "COPY\n"); | |||
if (0 != track_is_set_flag(track, FLAG_FOUR_CHANNEL)) | |||
fprintf(fp, "FOUR_CHANNEL_AUDIO\n"); | |||
if (NULL != track_get_isrc(track)) | |||
fprintf(fp, "ISRC \"%s\"\n", track_get_isrc(track)); | |||
if (0 != cdtext_is_empty(cdtext)) { | |||
fprintf(fp, "CD_TEXT {\n"); | |||
fprintf(fp, "\tLANGUAGE 0 {\n"); | |||
toc_print_cdtext(cdtext, fp, 1); | |||
fprintf(fp, "\t}\n"); | |||
fprintf(fp, "}\n"); | |||
} | |||
if (0 != track_get_zero_pre(track)) { | |||
fprintf(fp, "ZERO "); | |||
fprintf(fp, "%s", time_frame_to_mmssff(track_get_zero_pre(track))); | |||
fprintf(fp, "\n"); | |||
} | |||
fprintf(fp, "FILE "); | |||
fprintf(fp, "\"%s\" ", track_get_filename(track)); | |||
if (0 == track_get_start(track)) | |||
fprintf(fp, "0"); | |||
else | |||
fprintf(fp, "%s", time_frame_to_mmssff(track_get_start(track))); | |||
if (0 != track_get_length(track)) | |||
fprintf(fp, " %s", time_frame_to_mmssff(track_get_length(track))); | |||
fprintf(fp, "\n"); | |||
if (0 != track_get_zero_post(track)) { | |||
fprintf(fp, "ZERO "); | |||
fprintf(fp, "%s", time_frame_to_mmssff(track_get_zero_post(track))); | |||
fprintf(fp, "\n"); | |||
} | |||
if (track_get_index(track, 1) != 0) { | |||
fprintf(fp, "START "); | |||
fprintf(fp, "%s\n", time_frame_to_mmssff(track_get_index(track, 1))); | |||
} | |||
for (i = 2; i < track_get_nindex(track); i++) { | |||
fprintf(fp, "INDEX "); | |||
fprintf(fp, "%s\n", time_frame_to_mmssff( \ | |||
track_get_index(track, i) - track_get_index(track, 0) \ | |||
)); | |||
} | |||
} | |||
void toc_print_cdtext (Cdtext *cdtext, FILE *fp, int istrack) | |||
{ | |||
int pti; | |||
char *value = NULL; | |||
for (pti = 0; PTI_END != pti; pti++) { | |||
if (NULL != (value = cdtext_get(pti, cdtext))) { | |||
fprintf(fp, "\t\t"); | |||
fprintf(fp, "%s", cdtext_get_key(pti, istrack)); | |||
fprintf(fp, " \"%s\"\n", value); | |||
} | |||
} | |||
} |
@@ -0,0 +1,102 @@ | |||
%{ | |||
/* | |||
* toc_scan.l -- lexer for toc files | |||
* | |||
* Copyright (C) 2004 Svend Sorensen <sorensen@freeshell.org> | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "cd.h" | |||
#include "toc_parse.h" | |||
int toc_lineno = 1; | |||
%} | |||
ws [ \t\r] | |||
nonws [^ \t\r\n] | |||
%option noyywrap | |||
%s NAME | |||
%% | |||
\"(\\.|[^\\"])*\" { | |||
toc_yylval.sval = strdup(yytext + 1); | |||
toc_yylval.sval[strlen(toc_yylval.sval) - 1] = '\0'; | |||
BEGIN(INITIAL); | |||
return STRING; | |||
} | |||
<NAME>{nonws}+ { | |||
toc_yylval.sval = strdup(yytext); | |||
BEGIN(INITIAL); | |||
return STRING; | |||
} | |||
CATALOG { BEGIN(NAME); return CATALOG; } | |||
CD_DA { toc_yylval.ival = MODE_CD_DA; return CD_DA; } | |||
CD_ROM { toc_yylval.ival = MODE_CD_ROM; return CD_ROM; } | |||
CD_ROM_XA { toc_yylval.ival = MODE_CD_ROM_XA; return CD_ROM_XA; } | |||
TRACK { return TRACK; } | |||
AUDIO { toc_yylval.ival = MODE_AUDIO; return AUDIO; } | |||
MODE1 { toc_yylval.ival = MODE_MODE1; return MODE1; } | |||
MODE1_RAW { toc_yylval.ival = MODE_MODE1_RAW; return MODE1_RAW; } | |||
MODE2 { toc_yylval.ival = MODE_MODE2; return MODE2; } | |||
MODE2_FORM1 { toc_yylval.ival = MODE_MODE2_FORM1; return MODE2_FORM1; } | |||
MODE2_FORM2 { toc_yylval.ival = MODE_MODE2_FORM2; return MODE2_FORM2; } | |||
MODE2_FORM_MIX { toc_yylval.ival = MODE_MODE2_FORM_MIX; return MODE2_FORM_MIX; } | |||
MODE2_RAW { toc_yylval.ival = MODE_MODE2_RAW; return MODE2_RAW; } | |||
RW { toc_yylval.ival = SUB_MODE_RW; return RW; } | |||
RW_RAW { toc_yylval.ival = SUB_MODE_RW_RAW; return RW_RAW; } | |||
NO { return NO; } | |||
COPY { toc_yylval.ival = FLAG_PRE_EMPHASIS; return COPY; } | |||
PRE_EMPHASIS { toc_yylval.ival = FLAG_COPY_PERMITTED; return PRE_EMPHASIS; } | |||
FOUR_CHANNEL_AUDIO { toc_yylval.ival = FLAG_FOUR_CHANNEL; return FOUR_CHANNEL_AUDIO; } | |||
TWO_CHANNEL_AUDIO { toc_yylval.ival = FLAG_FOUR_CHANNEL; return TWO_CHANNEL_AUDIO; } | |||
/* ISRC is with CD-TEXT items */ | |||
SILENCE { return SILENCE; } | |||
ZERO { return ZERO; } | |||
(AUDIO)?FILE { BEGIN(NAME); return AUDIOFILE; } | |||
DATAFILE { BEGIN(NAME); return DATAFILE; } | |||
FIFO { BEGIN(NAME); return FIFO; } | |||
START { return START; } | |||
PREGAP { return PREGAP; } | |||
INDEX { return INDEX; } | |||
CD_TEXT { return CD_TEXT; } | |||
LANGUAGE_MAP { return LANGUAGE_MAP; } | |||
LANGUAGE { return LANGUAGE; } | |||
TITLE { BEGIN(NAME); toc_yylval.ival = PTI_TITLE; return TITLE; } | |||
PERFORMER { BEGIN(NAME); toc_yylval.ival = PTI_PERFORMER; return PERFORMER; } | |||
SONGWRITER { BEGIN(NAME); toc_yylval.ival = PTI_SONGWRITER; return SONGWRITER; } | |||
COMPOSER { BEGIN(NAME); toc_yylval.ival = PTI_COMPOSER; return COMPOSER; } | |||
ARRANGER { BEGIN(NAME); toc_yylval.ival = PTI_ARRANGER; return ARRANGER; } | |||
MESSAGE { BEGIN(NAME); toc_yylval.ival = PTI_MESSAGE; return MESSAGE; } | |||
DISC_ID { BEGIN(NAME); toc_yylval.ival = PTI_DISC_ID; return DISC_ID; } | |||
GENRE { BEGIN(NAME); toc_yylval.ival = PTI_GENRE; return GENRE; } | |||
TOC_INFO1 { BEGIN(NAME); toc_yylval.ival = PTI_TOC_INFO1; return TOC_INFO1; } | |||
TOC_INFO2 { BEGIN(NAME); toc_yylval.ival = PTI_TOC_INFO2; return TOC_INFO2; } | |||
UPC_EAN { BEGIN(NAME); toc_yylval.ival = PTI_UPC_ISRC; return UPC_EAN; } | |||
ISRC { BEGIN(NAME); toc_yylval.ival = PTI_UPC_ISRC; return ISRC; } | |||
SIZE_INFO { BEGIN(NAME); toc_yylval.ival = PTI_SIZE_INFO; return SIZE_INFO; } | |||
"//".*\n { toc_lineno++; /* ignore comments */ } | |||
{ws}+ { /* ignore whitespace */ } | |||
[[:digit:]]+ { toc_yylval.ival = atoi(yytext); return NUMBER; } | |||
:|,|\{|\} { return yytext[0]; } | |||
^{ws}*\n { toc_lineno++; /* blank line */ } | |||
\n { toc_lineno++; return '\n'; } | |||
. { fprintf(stderr, "bad character '%c'\n", yytext[0]); } | |||
%% |
@@ -0,0 +1,28 @@ | |||
# Makefile | |||
INSTALL= install | |||
INSTALL_PROGRAM= $(INSTALL) | |||
INSTALL_DATA= $(INSTALL) -m 644 | |||
prefix= /usr/local | |||
mandir= $(prefix)/man | |||
DESTDIR= | |||
TARGETS= cuebreakpoints.1 cueconvert.1 cueprint.1 | |||
all: | |||
@true | |||
install: all | |||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1 | |||
for i in $(TARGETS) ; do \ | |||
$(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/man1/$$i ; \ | |||
done | |||
uninstall: | |||
-for i in $(TARGETS) ; do \ | |||
rm -f $(DESTDIR)$(mandir)/man1/$$i ; \ | |||
done | |||
clean: | |||
@true |
@@ -0,0 +1,23 @@ | |||
.TH cuetools 1 | |||
.SH NAME | |||
cuebreakpoints | |||
.SH DESCRIPTION | |||
cuebreakpoints outputs the breakpoints from a cue or toc file | |||
.SH SYNTAX | |||
cueconvert [-h] [-i cue|toc] [-o cue|toc] [file...] | |||
.SH OPTIONS | |||
.TP | |||
.B \-h | |||
print usage information | |||
.TP | |||
.B \-i cue|toc | |||
set format of file(s) | |||
.SH NOTES | |||
The breakpoints are in a format usable by shnsplit (part of the shntool package). A track breakpoint is at index 1. | |||
.PP | |||
If no files are specified, stdin is used. If a filename is specified and the format is not specified, the format will be set based on a ".cue" or ".toc" suffix. | |||
.SH AUTHOR | |||
Svend Sorensen <sorensen@freeshell.org> | |||
.SH "SEE ALSO" | |||
cueconvert(1), | |||
cueprint(1) |
@@ -0,0 +1,24 @@ | |||
.TH cuetools 1 | |||
.SH NAME | |||
cueconvert | |||
.SH DESCRIPTION | |||
cueconvert converts between the cue and toc formats | |||
.SH SYNTAX | |||
cueconvert [-h] [-i cue|toc] [-o cue|toc] [infile [outfile]] | |||
.SH OPTIONS | |||
.TP | |||
.B \-h | |||
print usage information | |||
.TP | |||
.B \-i cue|toc | |||
set format of input file | |||
.TP | |||
.B \-i cue|toc | |||
set format of output file | |||
.SH NOTES | |||
If infile or outfile is not specified, stdin and stdout are used, respectively. If a filename is specified and the format is not specified, the format will be set based on a ".cue" or ".toc" suffix. If the output file format is not specified, and it cannot be determined from the suffix, it will be set to the opposite of the input format. | |||
.SH AUTHOR | |||
Svend Sorensen <sorensen@freeshell.org> | |||
.SH "SEE ALSO" | |||
cuebreakpoints(1), | |||
cueprint(1) |
@@ -0,0 +1,89 @@ | |||
.TH cuetools 1 | |||
.SH NAME | |||
cueprint | |||
.SH DESCRIPTION | |||
cueprint \- print disc and track infomation for a cue or toc file | |||
.SH SYNTAX | |||
cueprint [\-h] [\-i cue|toc] [\-d TEMPLATE] [\-t TEMPLATE] [file...] | |||
.SH OPTIONS | |||
.TP | |||
.B \-h | |||
print usage information | |||
.TP | |||
.B \-i cue|toc | |||
set format of file(s) | |||
.TP | |||
.B -d TEMPLATE | |||
set disc template (see TEMPLATE EXPANSION) | |||
.TP | |||
.B -t TEMPLATE | |||
set track template (see TEMPLATE EXPANSION) | |||
.SH TEMPLATE EXPANSION | |||
Disc template expansion characters are valid for both the disc and track templates. | |||
.PP | |||
Disc: | |||
.TP | |||
.B %A | |||
album arranger | |||
.TP | |||
.B %C | |||
album composer | |||
.TP | |||
.B %G | |||
album genre | |||
.TP | |||
.B %M | |||
album message | |||
.TP | |||
.B %N | |||
number of tracks | |||
.TP | |||
.B %P | |||
album performer | |||
.TP | |||
.B %S | |||
album songwriter | |||
.TP | |||
.B %T | |||
album title | |||
.TP | |||
.B %U | |||
album UPC/EAN | |||
.PP | |||
Track: | |||
.TP | |||
.B %a | |||
track arranger | |||
.TP | |||
.B %c | |||
track composer | |||
.TP | |||
.B %g | |||
track genre | |||
.TP | |||
.B %i | |||
track ISRC | |||
.TP | |||
.B %m | |||
track message | |||
.TP | |||
.B %n | |||
track number | |||
.TP | |||
.B %p | |||
track perfomer | |||
.TP | |||
.B %t | |||
track title | |||
.TP | |||
.B %u | |||
track ISRC (CD-TEXT) | |||
.PP | |||
Any other %<character> is expanded to that character. For example, %% expands to a literal `%'. | |||
.SH NOTES | |||
If no files are specified, stdin is used. If a filename is specified and the format is not specified, the format will be set based on a ".cue" or ".toc" suffix. | |||
.SH AUTHOR | |||
Svend Sorensen <sorensen@freeshell.org> | |||
.SH "SEE ALSO" | |||
cueconvert(1), | |||
cuebreakpoints(1) |
@@ -0,0 +1,52 @@ | |||
CATALOG 1234567890123 | |||
TITLE "Album Title" | |||
PERFORMER "Album Performer" | |||
SONGWRITER "Album Songwriter" | |||
COMPOSER "Album Composer" | |||
ARRANGER "Album Arranger" | |||
MESSAGE "Album Message" | |||
UPC_EAN "Album UPC/EAN" | |||
FILE "track1.wav" WAVE | |||
TRACK 01 AUDIO | |||
TITLE "Track 1 Title" | |||
PERFORMER "Track 1 Performer" | |||
SONGWRITER "Track 1 Songwriter" | |||
COMPOSER "Track 1 Composer" | |||
ARRANGER "Track 1 Arranger" | |||
MESSAGE "Track 1 Message" | |||
ISRC "CC-OWNR-99-12345" | |||
ISRC CCOWNR9912345 | |||
FLAGS PRE DCP 4CH SCMS | |||
INDEX 01 00:00:00 | |||
REM zero data pregap with index pregap | |||
TRACK 02 AUDIO | |||
TITLE "Track 2 Title" | |||
PERFORMER "Track 2 Performer" | |||
SONGWRITER "Track 2 Songwriter" | |||
COMPOSER "Track 2 Composer" | |||
ARRANGER "Track 2 Arranger" | |||
MESSAGE "Track 2 Message" | |||
ISRC "CC-OWNR-99-12345" | |||
ISRC CCOWNR9912345 | |||
FLAGS PRE DCP 4CH SCMS | |||
PREGAP 00:00:02 | |||
INDEX 00 05:00:00 | |||
INDEX 01 05:02:00 | |||
REM new file | |||
FILE "track3.wav" WAVE | |||
TRACK 03 AUDIO | |||
TITLE "Track 3 Title" | |||
PERFORMER "Track 3 Performer" | |||
SONGWRITER "Track 3 Songwriter" | |||
COMPOSER "Track 3 Composer" | |||
ARRANGER "Track 3 Arranger" | |||
MESSAGE "Track 3 Message" | |||
ISRC "CC-OWNR-99-12345" | |||
ISRC CCOWNR9912345 | |||
FLAGS PRE DCP 4CH SCMS | |||
INDEX 00 00:00:00 | |||
INDEX 01 00:03:00 | |||
POSTGAP 00:00:02 |
@@ -0,0 +1,60 @@ | |||
CATALOG 0000000000000 | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
TITLE "On Tour - Disc 1" | |||
FILE "marvin_gaye_and_freddie_jackson-2001-on_tour-cd1-kmf.wav" WAVE | |||
TRACK 01 AUDIO | |||
TITLE "I Heard It Through The Grapevine" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 00:00:00 | |||
TRACK 02 AUDIO | |||
TITLE "Come Get To This" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 03:57:64 | |||
TRACK 03 AUDIO | |||
TITLE "Let's Get In On" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 07:34:61 | |||
TRACK 04 AUDIO | |||
TITLE "God Is My Friend" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 12:56:41 | |||
TRACK 05 AUDIO | |||
TITLE "What's Going On" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 15:11:54 | |||
TRACK 06 AUDIO | |||
TITLE "Inner City Blues" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 19:10:33 | |||
TRACK 07 AUDIO | |||
TITLE "Joy" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 00 24:32:65 | |||
INDEX 01 24:34:35 | |||
TRACK 08 AUDIO | |||
TITLE "Medley (Ain't Nothing Like The Real Thing...)" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 29:03:56 | |||
TRACK 09 AUDIO | |||
TITLE "Rockin' After Midnight" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 37:23:42 | |||
TRACK 10 AUDIO | |||
TITLE "Distant Lover" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 46:21:21 | |||
TRACK 11 AUDIO | |||
TITLE "Sexual Healing" | |||
PERFORMER "Marvin Gaye and Freddie Jackson" | |||
FLAGS DCP | |||
INDEX 01 56:00:42 |
@@ -0,0 +1,336 @@ | |||
CD_DA | |||
CATALOG "0008811307523" | |||
CD_TEXT { | |||
LANGUAGE_MAP { | |||
0: 9 | |||
} | |||
LANGUAGE 0 { | |||
TITLE "Red Hot + Riot" | |||
PERFORMER "Various Artists" | |||
MESSAGE "Net Profits from the sale of this album will suport Red Jot's AIDS prevention and relief efforts in Africa and around the world. Produced By: John Carlin, Paul Heck and Andr\351s Levin" | |||
} | |||
} | |||
// Track 1 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214001" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "[intro] Fela Mentality" | |||
PERFORMER "Mix Master Mike and Mario Caldato, Jr." | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 0 01:09:45 | |||
// Track 2 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214002" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Kalakuta Show" | |||
PERFORMER "Mix Master Mike, Lateef, and The Gift Of Gab" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 01:09:45 02:31:17 | |||
// Track 3 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214003" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "[interlude] Live at Kalakuta" | |||
PERFORMER "Posma, Remedies, Taiwo, Segun, Tosin, Andres Levin" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 03:40:62 00:32:15 | |||
// Track 4 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214004" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Shuffering and Shmiling" | |||
PERFORMER "Dead Prez, Jorge Ben Jor, Talib Kweli, Bilal and Postive Force" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 04:13:02 07:50:05 | |||
// Track 5 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214005" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "[interlude] Gimme Shit" | |||
PERFORMER "Mix Master Mike and Mario Caldato, Jr." | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 12:03:07 00:31:43 | |||
// Track 6 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214006" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Water Get No Enemy [intro]" | |||
PERFORMER "D'Angelo and Femi Kuti" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 12:34:50 04:04:30 | |||
// Track 7 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214007" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Water Get No Enemy" | |||
PERFORMER "D'Angelo, Femi Kuti, and Macy Gray featuring Roy Hargrove, Nile Rodgers, The Soultronics, and Positive Force" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 16:39:05 06:05:70 | |||
// Track 8 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214007" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Gentleman" | |||
PERFORMER "Meshell Ndegeocello and Yerba Buena! featuring Ron Blake" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 22:45:00 07:02:70 | |||
// Track 9 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214009" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Tears and Sorrow" | |||
PERFORMER "Common, Meshell Ndegeocello, and Djelimady Tounkara" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 29:47:70 01:31:27 | |||
// Track 10 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214010" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Shakara Lady (part one)" | |||
PERFORMER "Cheikh Lo" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 31:19:22 02:20:05 | |||
// Track 11 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214011" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Shakara Lady (part two)" | |||
PERFORMER "Cheikh Lo, Les Nubians, and Manu Dibango featuring Chateau Flight" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 33:39:27 04:47:13 | |||
// Track 12 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214012" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "[interlude] Don't Worry About My Mouth-O" | |||
PERFORMER "Monoaural" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 38:26:40 01:03:32 | |||
// Track 13 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214013" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Zombie (part one)" | |||
PERFORMER "Bugz in the Attic featuring Wunmi" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 39:29:72 02:51:70 | |||
// Track 14 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214014" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Zombie (part two)" | |||
PERFORMER "Nile Rodgers, Roy Hargrove, and Money Mark" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 42:21:67 04:27:38 | |||
// Track 15 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214015" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "No Agreement" | |||
PERFORMER "Tony Allen, Res, Ray Lema, Baaba Maal, Postive Black Soul, and Archie Shepp" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 46:49:30 08:12:02 | |||
// Track 16 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214015" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "So Be It" | |||
PERFORMER "Kelis" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 55:01:32 03:52:15 | |||
// Track 17 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214016" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "[interlude] This is an Ashanti Proverb" | |||
PERFORMER "Monoaural" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 58:53:47 00:09:58 | |||
// Track 18 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "GBBBM0002184" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "By Your Side (Cottonbelly's Fola Mix Edit)" | |||
PERFORMER "Sade" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 59:03:30 04:39:67 | |||
// Track 19 | |||
TRACK AUDIO RW_RAW | |||
COPY | |||
PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214019" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Colonial Mentality" | |||
PERFORMER "Yerba Buena! and Lenine" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 63:43:22 01:34:10 | |||
START 00:00:01 | |||
INDEX 00:10:01 | |||
// Track 20 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
ISRC "USRH20214020" | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Trouble Sleep Yanga Wake Am" | |||
PERFORMER "Baaba Maal and Taj Mahal featuring Kaouding Cissoko and Antibalas" | |||
MESSAGE "" | |||
} | |||
} | |||
FILE "data.bin" 65:17:32 10:38:20 | |||
@@ -0,0 +1,208 @@ | |||
CD_DA | |||
CATALOG "0075994590127" | |||
CD_TEXT { | |||
LANGUAGE_MAP { | |||
0: 9 | |||
} | |||
LANGUAGE 0 { | |||
TITLE "Jagged Little Pill" | |||
PERFORMER "Alanis Morissette" | |||
MESSAGE "1995" | |||
} | |||
} | |||
// Track 1 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "All I Really Want" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
SILENCE 00:00:32 | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 0 04:43:28 | |||
START 00:00:32 | |||
// Track 2 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "You Oughta Know" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 04:43:28 04:09:00 | |||
START 00:01:20 | |||
// Track 3 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Perfect" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 08:52:28 03:07:65 | |||
START 00:01:35 | |||
// Track 4 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Hand in My Pocket" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 12:00:18 03:40:35 | |||
START 00:01:37 | |||
// Track 5 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Right Through You" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 15:40:53 02:57:00 | |||
START 00:02:55 | |||
// Track 6 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Forgiven" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 18:37:53 05:00:02 | |||
START 00:01:42 | |||
// Track 7 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "You Learn" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 23:37:55 04:00:33 | |||
START 00:01:60 | |||
// Track 8 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Head Over Feet" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 27:38:13 04:25:40 | |||
START 00:01:00 | |||
// Track 9 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Mary Jane" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 32:03:53 04:41:57 | |||
START 00:02:55 | |||
// Track 10 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Ironic" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 36:45:35 03:50:03 | |||
START 00:01:45 | |||
// Track 11 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Not the Doctor" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 40:35:38 03:46:25 | |||
START 00:01:20 | |||
// Track 12 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "Wake Up" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 44:21:63 04:56:03 | |||
START 00:02:40 | |||
// Track 13 | |||
TRACK AUDIO | |||
NO COPY | |||
NO PRE_EMPHASIS | |||
TWO_CHANNEL_AUDIO | |||
CD_TEXT { | |||
LANGUAGE 0 { | |||
TITLE "You Oughta Know (Alternate Take)" | |||
PERFORMER "Alanis Morissette" | |||
} | |||
} | |||
FILE "alanis_morissette-1998-jagged_little_pill-kmf.wav" 49:17:66 08:13:19 | |||
START 00:00:22 |
@@ -0,0 +1,39 @@ | |||
CPPFLAGS+= -I../lib | |||
LDFLAGS+= -L../lib | |||
LDLIBS+= -lcuefile | |||
TARGETS= cuebreakpoints cueconvert cueprint | |||
all: $(TARGETS) | |||
clean: | |||
rm -f $(TARGETS) | |||
rm -f *.o | |||
INSTALL= install | |||
INSTALL_PROGRAM= $(INSTALL) | |||
INSTALL_DATA= $(INSTALL) -m 644 | |||
prefix= /usr/local | |||
exec_prefix= $(prefix) | |||
bindir= $(exec_prefix)/bin | |||
DESTDIR= | |||
install: all | |||
$(INSTALL) -d $(DESTDIR)$(bindir) | |||
for i in $(TARGETS) ; do \ | |||
$(INSTALL_PROGRAM) $$i $(DESTDIR)$(bindir)/$$i ; \ | |||
done | |||
uninstall: | |||
-for i in $(TARGETS) ; do \ | |||
rm -f $(DESTDIR)$(bindir)/$$i ; \ | |||
done | |||
# dependancies | |||
# generated by `gcc -MM *.c' | |||
cuebreakpoints.o: cuebreakpoints.c ../lib/cuefile.h ../lib/cd.h \ | |||
../lib/cdtext.h | |||
cueconvert.o: cueconvert.c ../lib/cuefile.h ../lib/cd.h ../lib/cdtext.h | |||
cueprint.o: cueprint.c ../lib/cuefile.h ../lib/cd.h ../lib/cdtext.h |
@@ -0,0 +1,109 @@ | |||
/* | |||
* cuebreakpoints.c -- print track break points | |||
* | |||
* Copyright (C) 2004 Svend Sorensen | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include "cuefile.h" | |||
#include "time.h" | |||
char *progname; | |||
void usage (int status) | |||
{ | |||
if (0 == status) { | |||
fprintf(stdout, "%s: usage: cuebreakpoints [-h] [-i cue|toc] [file...]\n", progname); | |||
fputs("\ | |||
\n\ | |||
OPTIONS\n\ | |||
-h print usage\n\ | |||
-i cue|toc set format of file(s)\n\ | |||
", stdout); | |||
} else { | |||
fprintf(stderr, "%s: syntax error\n", progname); | |||
fprintf(stderr, "run `%s -h' for usage\n", progname); | |||
} | |||
exit (status); | |||
} | |||
void print_m_ss_ff (long frame) | |||
{ | |||
int m, s, f; | |||
time_frame_to_msf(frame, &m, &s, &f); | |||
printf ("%d:%02d.%02d\n", m, s, f); | |||
} | |||
void print_breaks (Cd *cd) | |||
{ | |||
int i; | |||
long b; | |||
Track *track; | |||
for (i = 1; i < cd_get_ntrack(cd); i++) { | |||
track = cd_get_track(cd, i); | |||
/* don't print zero indexes */ | |||
b = track_get_start(track) + track_get_index(track, 1) - track_get_zero_pre(track); | |||
if (0 != b) | |||
print_m_ss_ff(b); | |||
} | |||
} | |||
int breaks (char *name, int format) | |||
{ | |||
Cd *cd = NULL; | |||
if (NULL == (cd = cf_parse(name, &format))) { | |||
fprintf(stderr, "%s: input file error\n", name); | |||
return -1; | |||
} | |||
print_breaks(cd); | |||
return 0; | |||
} | |||
int main (int argc, char **argv) | |||
{ | |||
int format = UNKNOWN; | |||
/* option variables */ | |||
char c; | |||
/* getopt() variables */ | |||
extern char *optarg; | |||
extern int optind; | |||
progname = *argv; | |||
while (-1 != (c = getopt(argc, argv, "hi:"))) { | |||
switch (c) { | |||
case 'h': | |||
usage(0); | |||
break; | |||
case 'i': | |||
if (0 == strcmp("cue", optarg)) | |||
format = CUE; | |||
else if (0 == strcmp("toc", optarg)) | |||
format = TOC; | |||
break; | |||
default: | |||
usage(1); | |||
break; | |||
} | |||
} | |||
if (optind == argc) { | |||
breaks("-", format); | |||
} else { | |||
for (; optind < argc; optind++) | |||
breaks(argv[optind], format); | |||
} | |||
return 0; | |||
} |
@@ -0,0 +1,108 @@ | |||
/* | |||
* cueconvert.c -- convert between cue/toc formats | |||
* | |||
* Copyright (C) 2004 Svend Sorensen | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include "cuefile.h" | |||
char *progname; | |||
void usage (int status) | |||
{ | |||
if (0 == status) { | |||
fprintf(stdout, "%s: usage: cueconvert [-h] [-i cue|toc] [-o cue|toc] [infile [outfile]]\n", progname); | |||
fputs("\ | |||
\n\ | |||
OPTIONS\n\ | |||
-h print usage\n\ | |||
-i cue|toc set format of input file\n\ | |||
-o cue|toc set format of output file\n\ | |||
", stdout); | |||
} else { | |||
fprintf(stderr, "%s: syntax error\n", progname); | |||
fprintf(stderr, "run `%s -h' for usage\n", progname); | |||
} | |||
exit (status); | |||
} | |||
int convert (char *iname, int iformat, char *oname, int oformat) | |||
{ | |||
Cd *cd = NULL; | |||
if (NULL == (cd = cf_parse(iname, &iformat))) { | |||
fprintf(stderr, "input file error\n"); | |||
return -1; | |||
} | |||
if (UNKNOWN == oformat) { | |||
/* first use file suffix */ | |||
if (UNKNOWN == (oformat = cf_format_from_suffix(oname))) { | |||
/* then use opposite of input format */ | |||
switch(iformat) { | |||
case CUE: | |||
oformat = TOC; | |||
break; | |||
case TOC: | |||
oformat = CUE; | |||
break; | |||
} | |||
} | |||
} | |||
return cf_print(oname, &oformat, cd); | |||
} | |||
int main (int argc, char **argv) | |||
{ | |||
int iformat = UNKNOWN; | |||
int oformat = UNKNOWN; | |||
/* option variables */ | |||
char c; | |||
/* getopt() variables */ | |||
extern char *optarg; | |||
extern int optind; | |||
progname = *argv; | |||
while (-1 != (c = getopt(argc, argv, "hi:o:"))) { | |||
switch (c) { | |||
case 'h': | |||
usage(0); | |||
break; | |||
case 'i': | |||
if (0 == strcmp("cue", optarg)) | |||
iformat = CUE; | |||
else if (0 == strcmp("toc", optarg)) | |||
iformat = TOC; | |||
break; | |||
case 'o': | |||
if (0 == strcmp("cue", optarg)) | |||
oformat = CUE; | |||
else if (0 == strcmp("toc", optarg)) | |||
oformat = TOC; | |||
break; | |||
default: | |||
usage(1); | |||
break; | |||
} | |||
} | |||
if (optind == argc) { | |||
convert("-", iformat, "-", oformat); | |||
} else if (optind == argc - 1) { | |||
convert(argv[optind], iformat, "-", oformat); | |||
} else if (optind == argc - 2) { | |||
convert(argv[optind], iformat, argv[optind + 1], oformat); | |||
} else { | |||
usage(1); | |||
} | |||
return 0; | |||
} |
@@ -0,0 +1,240 @@ | |||
/* | |||
* cueprint.c -- print cd information based on a template | |||
* | |||
* Copyright (C) 2004 Svend Sorensen | |||
* For license terms, see the file COPYING in this distribution. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> /* exit() */ | |||
#include <string.h> /* strcmp() */ | |||
#include <unistd.h> /* getopt() */ | |||
#include <ctype.h> /* isdigit() */ | |||
#include "cuefile.h" | |||
/* default templates */ | |||
#define D_TEMPLATE "%P \"%T\" (%N tracks)\n" | |||
#define T_TEMPLATE "%n: %p \"%t\"\n" | |||
char *progname; | |||
char *d_template = D_TEMPLATE; /* disc template */ | |||
char *t_template = T_TEMPLATE; /* track template */ | |||
void usage (int status) | |||
{ | |||
if (0 == status) { | |||
fprintf(stdout, "%s: usage: cueprint [-h] [-i cue|toc] [-d TEMPLATE] [-t TEMPLATE] [file...]\n", progname); | |||
fputs("\ | |||
\n\ | |||
OPTIONS\n\ | |||
-h print usage\n\ | |||
-i cue|toc set format of file(s)\n\ | |||
-d TEMPLATE set disc template (see TEMPLATE EXPANSION)\n\ | |||
-t TEMPLATE set track template (see TEMPLATE EXPANSION)\n\ | |||
\n\ | |||
Template Expansion\n\ | |||
Disc:\n\ | |||
%A - album arranger\n\ | |||
%C - album composer\n\ | |||
%G - album genre\n\ | |||
%M - album message\n\ | |||
%N - number of tracks\n\ | |||
%P - album performer\n\ | |||
%S - album songwriter\n\ | |||
%T - album title\n\ | |||
%U - album UPC/EAN\n\ | |||
Track:\n\ | |||
%a - track arranger\n\ | |||
%c - track composer\n\ | |||
%g - track genre\n\ | |||
%i - track ISRC\n\ | |||
%m - track message\n\ | |||
%n - track number\n\ | |||
%p - track perfomer\n\ | |||
%t - track title\n\ | |||
%u - track ISRC (CD-TEXT)\n\ | |||
\n\ | |||
Any other %<character> is expanded to that character. For example, to get a\n\ | |||
'%', use %%.\n\ | |||
", stdout); | |||
fprintf(stdout, "default disc template is:\n\"%s\"\n", D_TEMPLATE); | |||
fprintf(stdout, "default track template is:\n\"%s\"\n", T_TEMPLATE); | |||
} else { | |||
fprintf(stderr, "%s: syntax error\n", progname); | |||
fprintf(stderr, "run `%s -h' for usage\n", progname); | |||
} | |||
exit (status); | |||
} | |||
void disc_field (char *c, Cd *cd) | |||
{ | |||
Cdtext *cdtext = NULL; | |||
cdtext = cd_get_cdtext(cd); | |||
switch (*c) { | |||
case 'A': | |||
printf("%s", cdtext_get(PTI_ARRANGER, cdtext)); | |||
break; | |||
case 'C': | |||
printf("%s", cdtext_get(PTI_COMPOSER, cdtext)); | |||
break; | |||
case 'G': | |||
printf("%s", cdtext_get(PTI_GENRE, cdtext)); | |||
break; | |||
case 'M': | |||
printf("%s", cdtext_get(PTI_MESSAGE, cdtext)); | |||
break; | |||
case 'N': | |||
printf("%0*d", 2, cd_get_ntrack(cd)); | |||
break; | |||
case 'P': | |||
printf("%s", cdtext_get(PTI_PERFORMER, cdtext)); | |||
break; | |||
case 'R': | |||
printf("%s", cdtext_get(PTI_ARRANGER, cdtext)); | |||
break; | |||
case 'S': | |||
printf("%s", cdtext_get(PTI_SONGWRITER, cdtext)); | |||
break; | |||
case 'T': | |||
printf("%s", cdtext_get(PTI_TITLE, cdtext)); | |||
break; | |||
case 'U': | |||
printf("%s", cdtext_get(PTI_UPC_ISRC, cdtext)); | |||
break; | |||
default: | |||
putchar(*c); | |||
break; | |||
} | |||
} | |||
void track_field (char *c, Cd *cd, int trackno) | |||
{ | |||
Track *track = NULL; | |||
Cdtext *cdtext = NULL; | |||
track = cd_get_track(cd, trackno); | |||
cdtext = track_get_cdtext(track); | |||
switch (*c) { | |||
case 'a': | |||
printf("%s", cdtext_get(PTI_ARRANGER, cdtext)); | |||
break; | |||
case 'c': | |||
printf("%s", cdtext_get(PTI_COMPOSER, cdtext)); | |||
break; | |||
case 'f': | |||
printf("%s", track_get_filename(track)); | |||
break; | |||
case 'g': | |||
printf("%s", cdtext_get(PTI_GENRE, cdtext)); | |||
break; | |||
case 'i': | |||
printf("%s", track_get_isrc(track)); | |||
break; | |||
case 'm': | |||
printf("%s", cdtext_get(PTI_MESSAGE, cdtext)); | |||
break; | |||
case 'n': | |||
printf("%0*d", 2, trackno); | |||
break; | |||
case 'p': | |||
printf("%s", cdtext_get(PTI_PERFORMER, cdtext)); | |||
break; | |||
case 's': | |||
printf("%s", cdtext_get(PTI_SONGWRITER, cdtext)); | |||
break; | |||
case 't': | |||
printf("%s", cdtext_get(PTI_TITLE, cdtext)); | |||
break; | |||
case 'u': | |||
printf("%s", cdtext_get(PTI_UPC_ISRC, cdtext)); | |||
break; | |||
default: | |||
disc_field(c, cd); | |||
break; | |||
} | |||
} | |||
void print_info (Cd *cd) | |||
{ | |||
int i; /* track */ | |||
char *c; | |||
for (c = d_template; '\0' != *c; c++) { | |||
if ('%' == *c) { | |||
c++; | |||
disc_field(c, cd); | |||
} else { | |||
putchar(*c); | |||
} | |||
} | |||
for (i = 1; i <= cd_get_ntrack(cd); i++) { | |||
for (c = t_template; '\0' != *c; c++) { | |||
if ('%' == *c) { | |||
c++; | |||
track_field(c, cd, i); | |||
} else { | |||
putchar(*c); | |||
} | |||
} | |||
} | |||
} | |||
int info (char *name, int format) | |||
{ | |||
Cd *cd = NULL; | |||
if (NULL == (cd = cf_parse(name, &format))) { | |||
fprintf(stderr, "%s: input file error\n", name); | |||
return -1; | |||
} | |||
print_info(cd); | |||
return 0; | |||
} | |||
int main (int argc, char **argv) | |||
{ | |||
int format = UNKNOWN; | |||
/* getopt () variables */ | |||
char c; | |||
extern char *optarg; | |||
extern int optind; | |||
progname = *argv; | |||
while (-1 != (c = getopt(argc, argv, "hi:d:t:"))) { | |||
switch (c) { | |||
case 'h': | |||
usage(0); | |||
break; | |||
case 'i': | |||
if (0 == strcmp("cue", optarg)) | |||
format = CUE; | |||
else if (0 == strcmp("toc", optarg)) | |||
format = TOC; | |||
break; | |||
case 'd': | |||
d_template = optarg; | |||
break; | |||
case 't': | |||
t_template = optarg; | |||
break; | |||
default: | |||
usage(1); | |||
break; | |||
} | |||
} | |||
if (optind == argc) { | |||
info("-", format); | |||
} else { | |||
for (; optind < argc; optind++) | |||
info(argv[optind], format); | |||
} | |||
return 0; | |||
} |