mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-07-31 07:59:30 +02:00
2025-04-28 Fred Gleason <fredg@paravelsystems.com>
* Removed nexgen_importer(1). Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
parent
162aa3e483
commit
ac9d282416
@ -25037,3 +25037,5 @@
|
|||||||
* Restored SHA1 hash code in 'lib/rdhash.cpp'.
|
* Restored SHA1 hash code in 'lib/rdhash.cpp'.
|
||||||
2025-04-28 Fred Gleason <fredg@paravelsystems.com>
|
2025-04-28 Fred Gleason <fredg@paravelsystems.com>
|
||||||
* Upgrade Qt dependency from Qt5 to Qt6.
|
* Upgrade Qt dependency from Qt5 to Qt6.
|
||||||
|
2025-04-28 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
* Removed nexgen_importer(1).
|
||||||
|
1
debian/rules.src
vendored
1
debian/rules.src
vendored
@ -24,7 +24,6 @@ binary:
|
|||||||
mkdir -p debian/rivendell-importers/usr/bin
|
mkdir -p debian/rivendell-importers/usr/bin
|
||||||
mv debian/tmp/usr/bin/wings_filter debian/rivendell-importers/usr/bin/
|
mv debian/tmp/usr/bin/wings_filter debian/rivendell-importers/usr/bin/
|
||||||
mv debian/tmp/usr/bin/rivendell_filter debian/rivendell-importers/usr/bin/
|
mv debian/tmp/usr/bin/rivendell_filter debian/rivendell-importers/usr/bin/
|
||||||
mv debian/tmp/usr/bin/nexgen_filter debian/rivendell-importers/usr/bin/
|
|
||||||
mv debian/tmp/usr/bin/crc-unity4k.sh debian/rivendell-importers/usr/bin/
|
mv debian/tmp/usr/bin/crc-unity4k.sh debian/rivendell-importers/usr/bin/
|
||||||
mv debian/tmp/usr/bin/rdcatch_copy debian/rivendell-importers/usr/bin/
|
mv debian/tmp/usr/bin/rdcatch_copy debian/rivendell-importers/usr/bin/
|
||||||
mv debian/tmp/usr/bin/panel_copy debian/rivendell-importers/usr/bin/
|
mv debian/tmp/usr/bin/panel_copy debian/rivendell-importers/usr/bin/
|
||||||
|
@ -28,16 +28,11 @@ MOC = @QT6_MOC@
|
|||||||
moc_%.cpp: %.h
|
moc_%.cpp: %.h
|
||||||
$(MOC) $< -o $@
|
$(MOC) $< -o $@
|
||||||
|
|
||||||
bin_PROGRAMS = nexgen_filter\
|
bin_PROGRAMS = panel_copy\
|
||||||
panel_copy\
|
|
||||||
rdcatch_copy\
|
rdcatch_copy\
|
||||||
rivendell_filter\
|
rivendell_filter\
|
||||||
wings_filter
|
wings_filter
|
||||||
|
|
||||||
dist_nexgen_filter_SOURCES = nexgen_filter.cpp nexgen_filter.h
|
|
||||||
nodist_nexgen_filter_SOURCES = moc_nexgen_filter.cpp
|
|
||||||
nexgen_filter_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT6_LIBS@ @MUSICBRAINZ_LIBS@ @IMAGEMAGICK_LIBS@
|
|
||||||
|
|
||||||
dist_panel_copy_SOURCES = panel_copy.cpp panel_copy.h
|
dist_panel_copy_SOURCES = panel_copy.cpp panel_copy.h
|
||||||
nodist_panel_copy_SOURCES = moc_panel_copy.cpp
|
nodist_panel_copy_SOURCES = moc_panel_copy.cpp
|
||||||
panel_copy_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT6_LIBS@ @MUSICBRAINZ_LIBS@ @IMAGEMAGICK_LIBS@
|
panel_copy_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT6_LIBS@ @MUSICBRAINZ_LIBS@ @IMAGEMAGICK_LIBS@
|
||||||
|
@ -1,690 +0,0 @@
|
|||||||
// nexgen_filter.cpp
|
|
||||||
//
|
|
||||||
// A Library import filter for the Prophet NexGen system
|
|
||||||
//
|
|
||||||
// (C) Copyright 2012-2023 Fred Gleason <fredg@paravelsystems.com>
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License version 2 as
|
|
||||||
// published by the Free Software Foundation.
|
|
||||||
//
|
|
||||||
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <rdapplication.h>
|
|
||||||
#include <rd.h>
|
|
||||||
#include <rdcart.h>
|
|
||||||
#include <rdconfig.h>
|
|
||||||
#include <rdconf.h>
|
|
||||||
#include <rdcmd_switch.h>
|
|
||||||
#include <rdcut.h>
|
|
||||||
#include <rddb.h>
|
|
||||||
#include <rdtempdirectory.h>
|
|
||||||
#include <rdwavefile.h>
|
|
||||||
#include <rdweb.h>
|
|
||||||
|
|
||||||
#include "nexgen_filter.h"
|
|
||||||
|
|
||||||
MainObject::MainObject(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
QString group_name;
|
|
||||||
QString audio_dir;
|
|
||||||
QString reject_dir="/dev/null";
|
|
||||||
QStringList xml_files;
|
|
||||||
bool ok=false;
|
|
||||||
char tempdir[PATH_MAX];
|
|
||||||
QString err_msg;
|
|
||||||
|
|
||||||
filter_cart_offset=0;
|
|
||||||
filter_delete_cuts=false;
|
|
||||||
filter_normalization_level=0;
|
|
||||||
filter_verbose=false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Open the Database
|
|
||||||
//
|
|
||||||
rda=static_cast<RDApplication *>(new RDCoreApplication("nexgen_filter",
|
|
||||||
"nexgen_filter",NEXGEN_FILTER_USAGE,false,this));
|
|
||||||
if(!rda->open(&err_msg,NULL,false,false)) {
|
|
||||||
fprintf(stderr,"nexgen_filter: %s\n",err_msg.toUtf8().constData());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Read Command Options
|
|
||||||
//
|
|
||||||
bool options=true;
|
|
||||||
for(unsigned i=0;i<rda->cmdSwitch()->keys();i++) {
|
|
||||||
if(!options) {
|
|
||||||
xml_files.push_back(rda->cmdSwitch()->key(i));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--verbose") {
|
|
||||||
filter_verbose=true;
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--group") {
|
|
||||||
group_name=rda->cmdSwitch()->value(i);
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--audio-dir") {
|
|
||||||
audio_dir=rda->cmdSwitch()->value(i);
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--reject-dir") {
|
|
||||||
reject_dir=rda->cmdSwitch()->value(i);
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--cart-offset") {
|
|
||||||
filter_cart_offset=rda->cmdSwitch()->value(i).toInt(&ok);
|
|
||||||
if(!ok) {
|
|
||||||
fprintf(stderr,"nexgen_filter: --cart-offset must be an integer\n");
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--delete-cuts") {
|
|
||||||
filter_delete_cuts=true;
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(rda->cmdSwitch()->key(i)=="--normalization-level") {
|
|
||||||
filter_normalization_level=rda->cmdSwitch()->value(i).toInt(&ok);
|
|
||||||
if(!ok) {
|
|
||||||
fprintf(stderr,"nexgen_filter: --cart-offset must be an integer\n");
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
if(filter_normalization_level>0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"nexgen_filter: positive --normalization-level is invalid\n");
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
rda->cmdSwitch()->setProcessed(i,true);
|
|
||||||
}
|
|
||||||
if(!rda->cmdSwitch()->processed(i)) {
|
|
||||||
options=false;
|
|
||||||
xml_files.push_back(rda->cmdSwitch()->key(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// RIPCD Connection
|
|
||||||
//
|
|
||||||
rda->ripc()->connectHost("localhost",RIPCD_TCP_PORT,rda->config()->password());
|
|
||||||
|
|
||||||
//
|
|
||||||
// Validate Arguments
|
|
||||||
//
|
|
||||||
if(group_name.isEmpty()) {
|
|
||||||
fprintf(stderr,"nexgen_filter: missing group name\n");
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
filter_group=new RDGroup(group_name);
|
|
||||||
if(!filter_group->exists()) {
|
|
||||||
fprintf(stderr,"nexgen_filter: group \"%s\" does not exist\n",
|
|
||||||
group_name.toUtf8().constData());
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
filter_audio_dir=new QDir(audio_dir);
|
|
||||||
if(!audio_dir.isEmpty()) {
|
|
||||||
if(!filter_audio_dir->exists()) {
|
|
||||||
fprintf(stderr,"nexgen_filter: audio directory \"%s\" does not exist\n",
|
|
||||||
audio_dir.toUtf8().constData());
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
if(!filter_audio_dir->isReadable()) {
|
|
||||||
fprintf(stderr,"nexgen_filter: audio directory \"%s\" is not readable\n",
|
|
||||||
audio_dir.toUtf8().constData());
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Configure Reject Directory
|
|
||||||
//
|
|
||||||
if(reject_dir=="/dev/null") {
|
|
||||||
filter_reject_dir=NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
filter_reject_dir=new QDir(reject_dir);
|
|
||||||
if(!filter_reject_dir->exists()) {
|
|
||||||
fprintf(stderr,"nexgen_filter: reject directory \"%s\" does not exist\n",
|
|
||||||
reject_dir.toUtf8().constData());
|
|
||||||
exit(256);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Create Temp Directory
|
|
||||||
//
|
|
||||||
strncpy(tempdir,(RDTempDirectory::basePath()+"/nexgen_filterXXXXXX").toUtf8(),
|
|
||||||
PATH_MAX-1);
|
|
||||||
filter_temp_dir=new QDir(mkdtemp(tempdir));
|
|
||||||
filter_temp_audiofile=filter_temp_dir->canonicalPath()+"/audio.dat";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Main Loop
|
|
||||||
//
|
|
||||||
for(int i=0;i<xml_files.size();i++) {
|
|
||||||
if(IsXmlFile(xml_files[i])) {
|
|
||||||
if(audio_dir.isEmpty()) {
|
|
||||||
fprintf(stderr,"unable to process \"%s\" [no --audio-dir specified]\n",
|
|
||||||
xml_files[i].toUtf8().constData());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ProcessXmlFile(xml_files[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ProcessArchive(xml_files[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Clean Up
|
|
||||||
//
|
|
||||||
rmdir(filter_temp_dir->canonicalPath().toUtf8());
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MainObject::ProcessArchive(const QString &filename)
|
|
||||||
{
|
|
||||||
int fd_in=-1;
|
|
||||||
int fd_out=-1;
|
|
||||||
char tempdir[PATH_MAX];
|
|
||||||
char *data=NULL;
|
|
||||||
QString dir;
|
|
||||||
char header[105];
|
|
||||||
uint32_t len;
|
|
||||||
QString xmlfile;
|
|
||||||
QString wavfile;
|
|
||||||
QStringList files;
|
|
||||||
struct stat stat;
|
|
||||||
blksize_t blksize=1024;
|
|
||||||
ssize_t n=0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Allocate Default Buffer
|
|
||||||
//
|
|
||||||
data=(char *)malloc(1024);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Create temporary directory
|
|
||||||
//
|
|
||||||
snprintf(tempdir,PATH_MAX,"%s/XXXXXX",
|
|
||||||
RDTempDirectory::basePath().toUtf8().constData());
|
|
||||||
if(mkdtemp(tempdir)==NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dir=tempdir;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Open Archive
|
|
||||||
//
|
|
||||||
if((fd_in=open(filename.toUtf8(),O_RDONLY))<0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Write Out File Components
|
|
||||||
//
|
|
||||||
while((read(fd_in,header,104)==104)&&(strncmp(header,"FR:",3)==0)) {
|
|
||||||
files.push_back(dir+"/"+RDGetBasePart(QString(header+3).replace("\\","/")));
|
|
||||||
if(files.back().right(4).toLower()==".xml") {
|
|
||||||
xmlfile=files.back();
|
|
||||||
}
|
|
||||||
if(files.back().right(4).toLower()==".wav") {
|
|
||||||
wavfile=files.back();
|
|
||||||
}
|
|
||||||
len=((0xFF&header[103])<<24)+((0xFF&header[102])<<16)+
|
|
||||||
((0xFF&header[101])<<8)+(0xFF&header[100]);
|
|
||||||
if((fd_out=open(files.back().toUtf8(),O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR))<0) {
|
|
||||||
fprintf(stderr,"unable to write temporary file \"%s\" [%s].\n",
|
|
||||||
files.back().toUtf8().constData(),strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(fstat(fd_out,&stat)==0) {
|
|
||||||
blksize=stat.st_blksize;
|
|
||||||
data=(char *)realloc(data,blksize);
|
|
||||||
}
|
|
||||||
for(uint32_t i=blksize;i<len;i+=blksize) {
|
|
||||||
n=read(fd_in,data,blksize);
|
|
||||||
RDCheckExitCode("ProcessArchive() write",write(fd_out,data,n));
|
|
||||||
}
|
|
||||||
n=read(fd_in,data,len%blksize);
|
|
||||||
RDCheckExitCode("ProcessArchive() write",write(fd_out,data,n));
|
|
||||||
close(fd_out);
|
|
||||||
}
|
|
||||||
close(fd_in);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Run Import
|
|
||||||
//
|
|
||||||
if((!xmlfile.isEmpty())&&(!wavfile.isEmpty())) {
|
|
||||||
ProcessXmlFile(xmlfile,wavfile,filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Clean Up
|
|
||||||
//
|
|
||||||
for(int i=0;i<files.size();i++) {
|
|
||||||
unlink(files[i].toUtf8());
|
|
||||||
}
|
|
||||||
rmdir(tempdir);
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MainObject::ProcessXmlFile(const QString &xml,const QString &wavname,
|
|
||||||
const QString &arcname)
|
|
||||||
{
|
|
||||||
RDCart *cart=NULL;
|
|
||||||
RDCut *cut=NULL;
|
|
||||||
RDWaveData data;
|
|
||||||
QString filename;
|
|
||||||
int cartnum;
|
|
||||||
QString sql;
|
|
||||||
RDSqlQuery *q;
|
|
||||||
QString delete_cuts_switch="";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Read Metadata
|
|
||||||
//
|
|
||||||
if(!OpenXmlFile(xml,&data,&cartnum,&filename)) {
|
|
||||||
fprintf(stderr,"unable to parse XML file \"%s\"\n",
|
|
||||||
xml.toUtf8().constData());
|
|
||||||
WriteReject(xml);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!wavname.isEmpty()) {
|
|
||||||
filename=wavname;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Sanity Checks
|
|
||||||
//
|
|
||||||
if((cartnum<1)||(cartnum>999999)) {
|
|
||||||
fprintf(stderr,"calculated cart number [%d] is invalid\n",cartnum);
|
|
||||||
WriteReject(xml);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(filter_group->enforceCartRange()) {
|
|
||||||
if((cartnum<(int)filter_group->defaultLowCart())||
|
|
||||||
(cartnum>(int)filter_group->defaultHighCart())) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"calculated cart number [%d] is invalid for group \"%s\"\n",
|
|
||||||
cartnum,filter_group->name().toUtf8().constData());
|
|
||||||
WriteReject(xml);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Prepare Audio
|
|
||||||
//
|
|
||||||
if(!PreprocessAudio(filename)) {
|
|
||||||
WriteReject(xml);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Import Audio
|
|
||||||
//
|
|
||||||
Print(QString::asprintf("Importing cart %06d",cartnum));
|
|
||||||
if(!data.title().isEmpty()) {
|
|
||||||
Print(QString::asprintf(" [%s",data.title().toUtf8().constData()));
|
|
||||||
if(!data.artist().isEmpty()) {
|
|
||||||
Print(QString::asprintf("/%s",data.artist().toUtf8().constData()));
|
|
||||||
}
|
|
||||||
Print(QString::asprintf("]"));
|
|
||||||
}
|
|
||||||
if(arcname.isEmpty()) {
|
|
||||||
Print(QString::asprintf(" from %s ...",filename.toUtf8().constData()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Print(QString::asprintf(" from %s ...",arcname.toUtf8().constData()));
|
|
||||||
}
|
|
||||||
if(filter_delete_cuts) {
|
|
||||||
delete_cuts_switch="--delete-cuts ";
|
|
||||||
}
|
|
||||||
QString cmd=QString("rdimport ")+
|
|
||||||
"--autotrim-level=0 "+
|
|
||||||
QString::asprintf("--normalization-level=%d ",filter_normalization_level)+
|
|
||||||
QString::asprintf("--to-cart=%d ",cartnum)+
|
|
||||||
delete_cuts_switch+
|
|
||||||
filter_group->name()+" "+
|
|
||||||
filter_temp_audiofile;
|
|
||||||
if(system(cmd.toUtf8())!=0) {
|
|
||||||
Print(QString::asprintf(" aborted.\n"));
|
|
||||||
fprintf(stderr,"import of \"%s\" failed\n",filename.toUtf8().constData());
|
|
||||||
WriteReject(xml);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Print(QString::asprintf(" done.\n"));
|
|
||||||
unlink(filter_temp_audiofile.toUtf8());
|
|
||||||
|
|
||||||
//
|
|
||||||
// Apply Metadata
|
|
||||||
//
|
|
||||||
cart=new RDCart(cartnum);
|
|
||||||
cart->setMetadata(&data);
|
|
||||||
delete cart;
|
|
||||||
sql=QString("select `CUT_NAME` from `CUTS` where ")+
|
|
||||||
QString::asprintf("`CART_NUMBER`=%d ",cartnum)+
|
|
||||||
"order by `ORIGIN_DATETIME` desc";
|
|
||||||
q=new RDSqlQuery(sql);
|
|
||||||
if(q->first()) {
|
|
||||||
cut=new RDCut(q->value(0).toString());
|
|
||||||
cut->setMetadata(&data);
|
|
||||||
delete cut;
|
|
||||||
}
|
|
||||||
delete q;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MainObject::OpenXmlFile(const QString &xml,RDWaveData *data,
|
|
||||||
int *cartnum,QString *filename)
|
|
||||||
{
|
|
||||||
FILE *f=NULL;
|
|
||||||
char line[1024];
|
|
||||||
int crossfade=-1;
|
|
||||||
int fadeup_start=-1;
|
|
||||||
int fadeup_len=-1;
|
|
||||||
|
|
||||||
if((f=fopen(xml.toUtf8(),"r"))==NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(fgets(line,1024,f)==NULL) {
|
|
||||||
fclose(f);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!QString(line).contains("XMLDAT")) {
|
|
||||||
fclose(f);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while(fgets(line,1024,f)!=NULL) {
|
|
||||||
ProcessXmlLine(line,data,cartnum,filename,&crossfade,&fadeup_start,
|
|
||||||
&fadeup_len);
|
|
||||||
}
|
|
||||||
if((fadeup_start>=0)&&(fadeup_len>=0)) { // Calculate Start Marker
|
|
||||||
data->setStartPos(fadeup_start);
|
|
||||||
data->setEndPos(data->endPos()+fadeup_start);
|
|
||||||
data->setFadeUpPos(fadeup_start+fadeup_len);
|
|
||||||
}
|
|
||||||
if((crossfade!=-1)&&(data->endPos()>0)) { // Calculate Segue
|
|
||||||
data->setSegueStartPos(data->endPos()-crossfade);
|
|
||||||
data->setSegueEndPos(data->endPos());
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MainObject::ProcessXmlLine(const QString &line,RDWaveData *data,
|
|
||||||
int *cartnum,QString *filename,
|
|
||||||
int *crossfade,int *fadeup_start,
|
|
||||||
int *fadeup_len)
|
|
||||||
{
|
|
||||||
QString tag=
|
|
||||||
line.mid(line.indexOf("<")+1,line.indexOf(">")-line.indexOf("<")-1).toLower();
|
|
||||||
QString value=line.mid(line.indexOf(">")+1,line.lastIndexOf("<")-line.indexOf(">")-1);
|
|
||||||
|
|
||||||
// printf("%s: %s\n",(const char *)tag,(const char *)value);
|
|
||||||
|
|
||||||
if(tag=="file_name") {
|
|
||||||
*filename=filter_audio_dir->canonicalPath()+"/"+
|
|
||||||
value.right(value.length()-value.lastIndexOf('\\')-1);
|
|
||||||
}
|
|
||||||
if(tag=="cart") {
|
|
||||||
*cartnum=value.toUInt()+filter_cart_offset;
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="title") {
|
|
||||||
data->setTitle(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="artist") {
|
|
||||||
data->setArtist(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="album") {
|
|
||||||
data->setAlbum(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="label") {
|
|
||||||
data->setLabel(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="composer") {
|
|
||||||
data->setComposer(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="licensor") {
|
|
||||||
data->setLicensingOrganization(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="user_define") {
|
|
||||||
data->setUserDefined(RDXmlUnescape(value));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="isrc") {
|
|
||||||
data->setIsrc(value.replace("-",""));
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="modified_time") {
|
|
||||||
QDateTime dt=GetDateTime(value);
|
|
||||||
data->setOriginationDate(dt.date());
|
|
||||||
data->setOriginationTime(dt.time());
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="start_time") {
|
|
||||||
QDateTime dt=GetDateTime(value);
|
|
||||||
data->setStartDate(dt.date());
|
|
||||||
data->setStartTime(dt.time());
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="end_time") {
|
|
||||||
QDateTime dt=GetDateTime(value);
|
|
||||||
data->setEndDate(dt.date());
|
|
||||||
data->setEndTime(dt.time());
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="intro_start") {
|
|
||||||
data->setStartPos(value.toInt());
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="intro_3") {
|
|
||||||
if(value.toInt()>0) {
|
|
||||||
data->setTalkStartPos(0);
|
|
||||||
data->setTalkEndPos(value.toInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(tag=="hookstart") {
|
|
||||||
if(value.toInt()>0) {
|
|
||||||
data->setHookStartPos(value.toInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(tag=="hookend") {
|
|
||||||
if(value.toInt()>0) {
|
|
||||||
data->setHookEndPos(value.toInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if(tag=="length") {
|
|
||||||
data->setEndPos(value.toInt());
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if(tag=="runtime") {
|
|
||||||
data->setEndPos(value.toInt());
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
if(tag=="isci_code") {
|
|
||||||
data->setIsci(value);
|
|
||||||
data->setMetadataFound(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Used for calculating segue markers later
|
|
||||||
//
|
|
||||||
if(tag=="cross_fade") {
|
|
||||||
*crossfade=value.toInt();
|
|
||||||
}
|
|
||||||
if(tag=="fade_up_start") {
|
|
||||||
*fadeup_start=value.toInt();
|
|
||||||
}
|
|
||||||
if(tag=="fade_up_length") {
|
|
||||||
*fadeup_len=value.toInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MainObject::PreprocessAudio(QString filename)
|
|
||||||
{
|
|
||||||
int fd=-1;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if((fd=open(filename.toUtf8(),O_RDONLY))<0) {
|
|
||||||
filename=SwapCase(filename);
|
|
||||||
if((fd=open(filename.toUtf8(),O_RDONLY))<0) {
|
|
||||||
fprintf(stderr,"unable to open audio file \"%s\"\n",
|
|
||||||
filename.toUtf8().constData());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
lseek(fd,20,SEEK_SET);
|
|
||||||
if(read(fd,&c,1)!=1) {
|
|
||||||
close(fd);
|
|
||||||
fprintf(stderr,"truncated audio file \"%s\"\n",filename.toUtf8().
|
|
||||||
constData());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
if(c==80) { // MPEG Audio
|
|
||||||
if(system((QString("madplay -Q -o wave:")+filter_temp_audiofile+" "+filename).toUtf8())!=0) {
|
|
||||||
fprintf(stderr,"MPEG converter error with file \"%s\"\n",
|
|
||||||
filename.toUtf8().constData());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // PCM Audio
|
|
||||||
if(symlink(filename.toUtf8(),filter_temp_audiofile.toUtf8())!=0) {
|
|
||||||
fprintf(stderr,"unable to create symlink \"%s\"\n",
|
|
||||||
filter_temp_audiofile.toUtf8().constData());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MainObject::WriteReject(const QString &filename)
|
|
||||||
{
|
|
||||||
if(filter_reject_dir!=NULL) {
|
|
||||||
if(QFile::exists(filename)) {
|
|
||||||
if(!RDCopy(filename,filter_reject_dir->canonicalPath()+"/"+
|
|
||||||
RDGetBasePart(filename))) {
|
|
||||||
fprintf(stderr,"Unable to write to \"%s\"\n",
|
|
||||||
filter_reject_dir->path().toUtf8().constData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QDateTime MainObject::GetDateTime(const QString &str) const
|
|
||||||
{
|
|
||||||
QStringList fields;
|
|
||||||
QStringList dates;
|
|
||||||
QStringList times;
|
|
||||||
QDateTime ret;
|
|
||||||
|
|
||||||
fields=str.split(" ");
|
|
||||||
if(fields.size()==2) {
|
|
||||||
dates=fields[0].split("/");
|
|
||||||
if(dates.size()==3) {
|
|
||||||
times=fields[1].split(":");
|
|
||||||
if(times.size()==3) {
|
|
||||||
ret=
|
|
||||||
QDateTime(QDate(dates[2].toInt(),dates[0].toInt(),dates[1].toInt()),
|
|
||||||
QTime(times[0].toInt(),times[1].toInt(),times[2].toInt()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString MainObject::SwapCase(const QString &str) const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
QStringList parts=str.split(".");
|
|
||||||
if(parts[parts.size()-1].
|
|
||||||
contains(QRegExp("*[a-z]*",Qt::CaseSensitive,QRegExp::Wildcard))>0) {
|
|
||||||
parts[parts.size()-1]=parts[parts.size()-1].toUpper();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
parts[parts.size()-1]=parts[parts.size()-1].toLower();
|
|
||||||
}
|
|
||||||
return parts.join(".");
|
|
||||||
*/
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MainObject::IsXmlFile(const QString &filename)
|
|
||||||
{
|
|
||||||
int fd=-1;
|
|
||||||
char data[10];
|
|
||||||
|
|
||||||
if((fd=open(filename.toUtf8(),O_RDONLY))<0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(read(fd,data,8)!=8) {
|
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
data[8]=0;
|
|
||||||
return strncmp(data,"<XMLDAT>",8)==0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MainObject::Print(const QString &msg) const
|
|
||||||
{
|
|
||||||
if(filter_verbose) {
|
|
||||||
printf("%s",msg.toUtf8().constData());
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc,char *argv[])
|
|
||||||
{
|
|
||||||
QCoreApplication a(argc,argv,false);
|
|
||||||
new MainObject(NULL);
|
|
||||||
return a.exec();
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
// nexgen_filter.h
|
|
||||||
//
|
|
||||||
// A Library import filter for the Prophet NexGen system
|
|
||||||
//
|
|
||||||
// (C) Copyright 2012,2018 Fred Gleason <fredg@paravelsystems.com>
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License version 2 as
|
|
||||||
// published by the Free Software Foundation.
|
|
||||||
//
|
|
||||||
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef NEXGEN_FILTER_H
|
|
||||||
#define NEXGEN_FILTER_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <qapplication.h>
|
|
||||||
#include <qdatetime.h>
|
|
||||||
#include <qdir.h>
|
|
||||||
#include <qobject.h>
|
|
||||||
|
|
||||||
#include <rdgroup.h>
|
|
||||||
#include <rdwavedata.h>
|
|
||||||
|
|
||||||
#define NEXGEN_FILTER_USAGE "[options] <xml-file>|<pkt-file> [...]\n\nImport audio from a Prophet NexGen system, using metadata contained in\none or more XML files. Options are:\n\n--group=<group-name>\n The Rivendell group to use. This option is mandatory and has no default.\n\n--audio-dir=<path>\n The full path to the directory containing the audio files. This option\n is ignored when importing PKT files, but mandatory for importing\n using XML data. It has no default.\n\n--reject-dir=<path>\n The full path to the directory in which to place copies of XML files\n which were unable to be processed. Default is '/dev/null'.\n\n--cart-offset=<offset>\n Apply integer <offset> to the NexGen cart number before importing.\n Default is '0'.\n\n--delete-cuts\n If the destination cart already exists, delete any existing cuts\n within it before importing.\n\n--normalization-level=<level>\n The level to use for normalizing the audio, in dBFS. Specifying '0'\n will turn off normalization. Default is '0'.\n\n--verbose\n Print status messages as files are processed.\n\n<xml-file> [..]\n Filespec for XML file(s) containing import metadata.\n\n"
|
|
||||||
|
|
||||||
class MainObject : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
MainObject(QObject *parent=0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void ProcessArchive(const QString &filename);
|
|
||||||
void ProcessXmlFile(const QString &xml,const QString &wavname="",
|
|
||||||
const QString &arcname="");
|
|
||||||
bool OpenXmlFile(const QString &xml,RDWaveData *data,int *cartnum,
|
|
||||||
QString *filename);
|
|
||||||
void ProcessXmlLine(const QString &line,RDWaveData *data,int *cartnum,
|
|
||||||
QString *filename,int *crossfade,int *fadeup_start,
|
|
||||||
int *fadeup_len);
|
|
||||||
bool PreprocessAudio(QString filename);
|
|
||||||
void WriteReject(const QString &filename);
|
|
||||||
QDateTime GetDateTime(const QString &str) const;
|
|
||||||
QString SwapCase(const QString &str) const;
|
|
||||||
bool IsXmlFile(const QString &filename);
|
|
||||||
void Print(const QString &msg) const;
|
|
||||||
RDGroup *filter_group;
|
|
||||||
QDir *filter_audio_dir;
|
|
||||||
QDir *filter_reject_dir;
|
|
||||||
QDir *filter_temp_dir;
|
|
||||||
QString filter_temp_audiofile;
|
|
||||||
int filter_cart_offset;
|
|
||||||
bool filter_delete_cuts;
|
|
||||||
int filter_normalization_level;
|
|
||||||
bool filter_verbose;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -71,7 +71,7 @@ audio are also included.
|
|||||||
%description importers
|
%description importers
|
||||||
This package contains various importer scripts, which can be used to
|
This package contains various importer scripts, which can be used to
|
||||||
import audio from existing legacy automation systems into Rivendell.
|
import audio from existing legacy automation systems into Rivendell.
|
||||||
Currently, scripts exist for the AirForce Wings, Prophet NexGen and Sierra
|
Currently, scripts exist for the AirForce Wings and Sierra
|
||||||
Automated Systems SASAuto systems, as well as from another Rivendell system
|
Automated Systems SASAuto systems, as well as from another Rivendell system
|
||||||
(useful for 'merging' multiple databases). Additionally, scripts for
|
(useful for 'merging' multiple databases). Additionally, scripts for
|
||||||
initializing switcher matrices for the Christian Radio Consortium
|
initializing switcher matrices for the Christian Radio Consortium
|
||||||
@ -526,7 +526,6 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
%files importers
|
%files importers
|
||||||
%{_bindir}/wings_filter
|
%{_bindir}/wings_filter
|
||||||
%{_bindir}/rivendell_filter
|
%{_bindir}/rivendell_filter
|
||||||
%{_bindir}/nexgen_filter
|
|
||||||
%{_bindir}/crc-unity4k.sh
|
%{_bindir}/crc-unity4k.sh
|
||||||
%{_bindir}/rdcatch_copy
|
%{_bindir}/rdcatch_copy
|
||||||
%{_bindir}/panel_copy
|
%{_bindir}/panel_copy
|
||||||
|
Loading…
x
Reference in New Issue
Block a user