diff options
Diffstat (limited to 'tdeioslave/audiocd')
39 files changed, 6096 insertions, 0 deletions
diff --git a/tdeioslave/audiocd/HACKING b/tdeioslave/audiocd/HACKING new file mode 100644 index 00000000..dde6efc1 --- /dev/null +++ b/tdeioslave/audiocd/HACKING @@ -0,0 +1,25 @@ +// CODE LAYOUT + +audiocd.[h,cpp] - The main ioslave code. It contains the logic to rip audio from cd's. It loads all of the plugins that it can find. When it needs to encode, generate directories (and names of directories) it goes through it's list. audiocd uses libkcddb to retrieve its cddb entries and cdparinoia to retrieve the audio from the CD. + +plugins/audiocdencoder.[h,cpp] - The base class for all of the encoder plugins + +plugins/wav/* - The cda and wav "encoders" +plugins/flac/* - the flac encoder +plugins/lame/* - The mp3 encoder +plugins/vorbis/* - The ogg encoder + +kcmaudiocd/ - kcm configure dialog for the audiocd ioslave. It also loads the plugins and gets their configure dialogs and puts them into the tab dialog. + +// USERS + +Audiocd's "interface" is presented first to the users, It should be simple. The number of files/directories should be kept to a minimum. + +// APP SKIMMING + +Audiocd also has the ability to be "skimmed" by other tools. For example an outside application could retrieve the second track with: + +audiocd:/Wav/Track 02.wav?device=/dev/hd2&fileNameTemplate=Track %{number}&cddbChoice=1 + +This way apps can just query audiocd:/ for CDDB, present them to the users, and rip the tracks all without having to impliment it themselves. + diff --git a/tdeioslave/audiocd/Makefile.am b/tdeioslave/audiocd/Makefile.am new file mode 100644 index 00000000..8e190d4e --- /dev/null +++ b/tdeioslave/audiocd/Makefile.am @@ -0,0 +1,33 @@ +if include_kcm_audiocd +AUDIO_CD_SUBDIRS = kcmaudiocd +endif +SUBDIRS = plugins $(AUDIO_CD_SUBDIRS) + +INCLUDES = -I$(top_srcdir)/libkcddb \ + -I$(top_builddir)/libkcddb $(all_includes) \ + -I$(top_srcdir)/kscd $(all_includes) \ + -I$(srcdir)/plugins $(all_includes) + +KDE_CXXFLAGS=$(ENABLE_PERMISSIVE_FLAG) + +kde_module_LTLIBRARIES = kio_audiocd.la + +kio_audiocd_la_SOURCES = audiocd.cpp + +kio_audiocd_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +kio_audiocd_la_LIBADD = ./plugins/libaudiocdplugins.la $(LIB_KIO) $(CDPARANOIA_LIBS) $(top_builddir)/libkcddb/libkcddb.la $(top_builddir)/kscd/libkcompactdisc.la + +noinst_HEADERS = audiocd.h + +protocoldir = $(kde_servicesdir) +protocol_DATA = audiocd.protocol + +messages: + $(XGETTEXT) *.cpp -o $(podir)/tdeio_audiocd.pot + +updatedir = $(kde_datadir)/tdeconf_update +update_DATA = audiocd.upd +update_SCRIPTS = upgrade-metadata.sh + +audiocd.lo: ../../libkcddb/configbase.h diff --git a/tdeioslave/audiocd/audiocd.cpp b/tdeioslave/audiocd/audiocd.cpp new file mode 100644 index 00000000..7898be5a --- /dev/null +++ b/tdeioslave/audiocd/audiocd.cpp @@ -0,0 +1,1159 @@ +/* + * Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + * Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + * Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + * Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + * Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + * + * 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 + * ERCHANTABILITY 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <config.h> + +extern "C" +{ + #include <cdda_interface.h> + #include <cdda_paranoia.h> + void paranoiaCallback(long, int); + + #include <kdemacros.h> + KDE_EXPORT int kdemain(int argc, char ** argv); +} + +#include "audiocd.h" +#include "plugins/audiocdencoder.h" + +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <kmacroexpander.h> +#include <tqfile.h> +#include <tqfileinfo.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kapplication.h> +#include <klocale.h> +#include <tqregexp.h> + +// CDDB +#include <client.h> +#include "kcompactdisc.h" + +using namespace TDEIO; +using namespace KCDDB; + +#define TQFL1(x) TQString::fromLatin1(x) +#define DEFAULT_CD_DEVICE "/dev/cdrom" +#define CDDB_INFORMATION "CDDB Information" + +using namespace AudioCD; + +static const KCmdLineOptions options[] = +{ + { "+protocol", I18N_NOOP("Protocol name"), 0 }, + { "+pool", I18N_NOOP("Socket name"), 0 }, + { "+app", I18N_NOOP("Socket name"), 0 }, + KCmdLineLastOption +}; + +int kdemain(int argc, char ** argv) +{ + // TDEApplication uses libkcddb which needs a valid kapp pointer + // GUIenabled must be true as libkcddb sometimes wants to communicate + // with the user + putenv(strdup("SESSION_MANAGER=")); + TDEApplication::disableAutoDcopRegistration(); + TDECmdLineArgs::init(argc, argv, "kio_audiocd", 0, 0, 0, 0); + TDECmdLineArgs::addCmdLineOptions(options); + TDEApplication app(false, true); + + kdDebug(7117) << "Starting " << getpid() << endl; + + TDECmdLineArgs* args = TDECmdLineArgs::parsedArgs(); + AudioCDProtocol slave(args->arg(0), args->arg(1), args->arg(2)); + slave.dispatchLoop(); + + kdDebug(7117) << "Done" << endl; + return 0; +} + +enum Which_dir { + Unknown = 0, // Error + Info, // CDDB info + Root, // The root directory, shows all these :) + FullCD, // Show a single file containing all of the data + EncoderDir // A directory created by an encoder +}; + +class AudioCDProtocol::Private { +public: + Private() : cd(KCompactDisc::Asynchronous) { + clearURLargs(); + s_info = i18n("Information"); + s_fullCD = i18n("Full CD"); + } + + void clearURLargs() { + req_allTracks = false; + which_dir = Unknown; + req_track = -1; + cddbUserChoice = -1; + } + + // The type/which of request + bool req_allTracks; + Which_dir which_dir; + int req_track; + TQString fname; + AudioCDEncoder *encoder_dir_type; + + // Misc settings + TQString device; // URL settable + int paranoiaLevel; // URL settable + bool reportErrors; + + // Directory strings, never change after init + TQString s_info; + TQString s_fullCD; + + // Current CD + unsigned discid; + unsigned tracks; + bool trackIsAudio[100]; + KCompactDisc cd; // keep it around so that we don't assume the disk changed between every stat() + + // CDDB items + KCDDB::CDDB::Result cddbResult; + CDInfoList cddbList; + int cddbUserChoice; // URL settable + KCDDB::CDInfo cddbBestChoice; + + // Template for .. + TQString fileNameTemplate; // URL settable + TQString albumTemplate; // URL settable + TQString rsearch; + TQString rreplace; + + // Current strings for this CD and or cddb selection + TQStringList templateTitles; + TQString templateAlbumName; +}; + +int paranoia_read_limited_error; + +AudioCDProtocol::AudioCDProtocol(const TQCString & protocol, const TQCString & pool, const TQCString & app) + : SlaveBase(protocol, pool, app) +{ + d = new Private; + + // Add encoders + AudioCDEncoder::findAllPlugins(this, encoders); + encoderTypeCDA = encoderFromExtension(".cda"); + encoderTypeWAV = encoderFromExtension(".wav"); + encoders.setAutoDelete(true); +} + +AudioCDProtocol::~AudioCDProtocol() +{ + delete d; +} + +AudioCDEncoder *AudioCDProtocol::encoderFromExtension(const TQString& extension) +{ + AudioCDEncoder *encoder; + for ( encoder = encoders.first(); encoder; encoder = encoders.next() ){ + if(TQString(".")+encoder->fileType() == extension) + return encoder; + } + Q_ASSERT(false); + return NULL; +} + +AudioCDEncoder *AudioCDProtocol::determineEncoder(const TQString & filename) +{ + int len = filename.length(); + int pos = filename.findRev('.'); + return encoderFromExtension(filename.right(len - pos)); +} + +struct cdrom_drive * AudioCDProtocol::initRequest(const KURL & url) +{ + if (url.hasHost()) + { + error(TDEIO::ERR_UNSUPPORTED_ACTION, + i18n("You cannot specify a host with this protocol. " + "Please use the audiocd:/ format instead.")); + return 0; + } + + // Load OUR Settings. + loadSettings(); + // Then url parameters can overrule our settings. + parseURLArgs(url); + + struct cdrom_drive * drive = getDrive(); + if (0 == drive) + return 0; + + // Update our knowledge of the disc + +#if defined(__linux__) + if(drive->ioctl_device_name && drive->ioctl_device_name[0]) + d->cd.setDevice(drive->ioctl_device_name, 50, false); + else + d->cd.setDevice(drive->cdda_device_name, 50, false); +#else + d->cd.setDevice(drive->cdda_device_name, 50, false); +#endif + +#if 0 + // FreeBSD's cdparanoia as of january 5th 2006 has rather broken + // support for non-SCSI devices. Although it finds ATA cdroms just + // fine, there is no straightforward way to discover the device + // name associated with the device, which throws the rest of audiocd + // for a loop. + // + if ( !(drive->dev) || (COOKED_IOCTL == drive->interface) ) + { + // For ATAPI devices, we have no real choice. Use the + // user selected value, even if there is none. + // + kdWarning(7117) << "Found an ATAPI device, assuming it is the one specified by the user." << endl; + d->cd.setDevice( d->device ); + } + else + { + kdDebug(7117) << "Found a SCSI or ATAPICAM device." << endl; + if ( strlen(drive->dev->device_path) > 0 ) + { + d->cd.setDevice( drive->dev->device_path ); + } + else + { + // But the device_path can be empty under some + // circumstances, so build a representation from + // the unit number and SCSI device name. + // + TQString devname = TQString::fromLatin1( "/dev/%1%2" ) + .arg( drive->dev->given_dev_name ) + .arg( drive->dev->given_unit_number ) ; + kdDebug(7117) << " Using derived name " << devname << endl; + d->cd.setDevice( devname ); + } + } +#endif + + if (d->cd.discId() != d->discid && d->cd.discId() != d->cd.missingDisc){ + d->discid = d->cd.discId(); + d->tracks = d->cd.tracks(); + for(uint i=0; i< d->cd.tracks(); i++) + d->trackIsAudio[i] = d->cd.isAudio(i+1); + + KCDDB::Client c; + d->cddbResult = c.lookup(d->cd.discSignature()); + d->cddbList = c.lookupResponse(); + d->cddbBestChoice = c.bestLookupResponse(); + generateTemplateTitles(); + } + + // Determine what file or folder that is wanted. + d->fname = url.fileName(false); + TQString dname = url.directory(true, false); + if (!dname.isEmpty() && dname[0] == '/') + dname = dname.mid(1); + + // Kong issue where they send dirs as files, double check + /* A hack, for when konqi wants to list the directory audiocd:/Bla + it really submits this URL, instead of audiocd:/Bla/ to us. We could + send (in listDir) the UDS_NAME as "Bla/" for directories, but then + konqi shows them as "Bla//" in the status line. */ + // See if it is an encoder directory + AudioCDEncoder *encoder; + for ( encoder = encoders.first(); encoder; encoder = encoders.next() ){ + if(encoder->type() == d->fname){ + dname = d->fname; + d->fname = ""; + break; + } + } + // Other Hard coded directories + if (dname.isEmpty() && (d->fname == d->s_info || d->fname == d->s_fullCD )) + { + dname = d->fname; + d->fname = ""; + } + // end hack + + + // See which directory they want + d->which_dir = Unknown; + for ( encoder = encoders.first(); encoder; encoder = encoders.next() ){ + if(encoder->type() == dname){ + d->which_dir = EncoderDir; + d->encoder_dir_type = encoder; + break; + } + } + if ( Unknown == d->which_dir ){ + if (dname.isEmpty()) + d->which_dir = Root; + else if (dname == d->s_info) + d->which_dir = Info; + else if (dname == d->s_fullCD) + d->which_dir = FullCD; + } + + // See if the url is a track + d->req_track = -1; + if (!d->fname.isEmpty()){ + TQString name(d->fname); + + // Remove extension + int dot = name.findRev('.'); + if (dot >= 0) + name.truncate(dot); + + // See if it matches a cddb title + uint trackNumber; + for (trackNumber = 0; trackNumber < d->tracks; trackNumber++){ + if (d->templateTitles[trackNumber] == name) + break; + } + if (trackNumber < d->tracks) + d->req_track = trackNumber; + else { + /* Not found in title list. Try hard to find a number in the + string. */ + unsigned int start = 0; + unsigned int end = 0; + // Find where the numbers start + while (start < name.length()){ + if (name[start++].isDigit()) + break; + } + // Find where the numbers end + for (end = start; end < name.length(); end++) + if (!name[end].isDigit()) + break; + if (start < name.length()){ + bool ok; + // The external representation counts from 1 so subtrac 1. + d->req_track = name.mid(start-1, end - start+2).toInt(&ok) - 1; + if (!ok) + d->req_track = -1; + } + } + } + if (d->req_track >= (int)d->tracks) + d->req_track = -1; + + // Are we in the directory that lists "full CD" files? + d->req_allTracks = (dname.contains(d->s_fullCD)); + + kdDebug(7117) << "dir=" << dname << " file=" << d->fname + << " req_track=" << d->req_track << " which_dir=" << d->which_dir << " full CD?=" << d->req_allTracks << endl; + return drive; +} + +bool AudioCDProtocol::getSectorsForRequest(struct cdrom_drive * drive, long & firstSector, long & lastSector) const +{ + if (d->req_allTracks) + { // we rip all the tracks of the CD + firstSector = cdda_track_firstsector(drive, 1); + lastSector = cdda_track_lastsector(drive, cdda_tracks(drive)); + } + else + { // we only rip the selected track + int trackNumber = d->req_track + 1; + + if (trackNumber <= 0 || trackNumber > cdda_tracks(drive)) + return false; + firstSector = cdda_track_firstsector(drive, trackNumber); + lastSector = cdda_track_lastsector(drive, trackNumber); + } + return true; +} + +void AudioCDProtocol::get(const KURL & url) +{ + struct cdrom_drive * drive = initRequest(url); + if (!drive) + return; + + if( d->fname.contains(i18n(CDDB_INFORMATION))){ + uint choice = 1; + if(d->fname != TQString("%1.txt").arg(i18n(CDDB_INFORMATION))){ + choice= d->fname.section('_',1,1).section('.',0,0).toInt(); + } + uint count = 1; + CDInfoList::iterator it; + bool found = false; + for ( it = d->cddbList.begin(); it != d->cddbList.end(); ++it ){ + if(count == choice){ + mimeType("text/html"); + data(TQCString( (*it).toString().latin1() )); + // send an empty TQByteArray to signal end of data. + data(TQByteArray()); + finished(); + found = true; + break; + } + count++; + } + if(!found && d->fname.contains(i18n(CDDB_INFORMATION)+":")){ + mimeType("text/html"); + //data(TQCString( d->fname.latin1() )); + // send an empty TQByteArray to signal end of data. + data(TQByteArray()); + finished(); + found = true; + } + if( !found ) + error(TDEIO::ERR_DOES_NOT_EXIST, url.path()); + cdda_close(drive); + return; + } + + long firstSector, lastSector; + if (!getSectorsForRequest(drive, firstSector, lastSector)) + { + error(TDEIO::ERR_DOES_NOT_EXIST, url.path()); + cdda_close(drive); + return; + } + + AudioCDEncoder *encoder = determineEncoder(d->fname); + if(!encoder){ + cdda_close(drive); + return; + } + + KCDDB::CDInfo info; + if(d->cddbResult == KCDDB::CDDB::Success){ + info = d->cddbBestChoice; + + int track = d->req_track; + + // hack + // do we rip the whole CD? + if (d->req_allTracks){ + track = 0; + // YES => the title of the file is the title of the CD + info.trackInfoList[track].title = info.title.utf8().data(); + } + encoder->fillSongInfo(info, track, ""); + } + long totalByteCount = CD_FRAMESIZE_RAW * (lastSector - firstSector + 1); + long time_secs = (8 * totalByteCount) / (44100 * 2 * 16); + + unsigned long size = encoder->size(time_secs); + totalSize(size); + emit mimeType(TQFL1(encoder->mimeType())); + + // Read data (track/disk) from the cd + paranoiaRead(drive, firstSector, lastSector, encoder, url.fileName(), size); + + // send an empty TQByteArray to signal end of data. + data(TQByteArray()); + + cdda_close(drive); + + finished(); +} + +void AudioCDProtocol::stat(const KURL & url) +{ + struct cdrom_drive * drive = initRequest(url); + if (!drive) + return; + + bool isFile = !d->fname.isEmpty(); + + // the track number. 0 if ripping + // the whole CD. + uint trackNumber = d->req_track + 1; + + if (!d->req_allTracks) + { // we only want to rip one track. + // does this track exist? + if (isFile && (trackNumber < 1 || trackNumber > d->tracks)) + { + error(TDEIO::ERR_DOES_NOT_EXIST, url.path()); + return; + } + } + + UDSEntry entry; + + UDSAtom atom; + atom.m_uds = TDEIO::UDS_NAME; + atom.m_str = url.fileName().replace('/', TQFL1("%2F")); + kdDebug(7117) << k_funcinfo << atom.m_str << endl; + entry.append(atom); + + atom.m_uds = TDEIO::UDS_FILE_TYPE; + atom.m_long = isFile ? S_IFREG : S_IFDIR; + entry.append(atom); + + const mode_t _umask = ::umask(0); + ::umask(_umask); + + atom.m_uds = TDEIO::UDS_ACCESS; + atom.m_long = 0666 & (~_umask); + entry.append(atom); + + atom.m_uds = TDEIO::UDS_SIZE; + if (!isFile) + { + atom.m_long = cdda_tracks(drive); + } + else + { + AudioCDEncoder *encoder = determineEncoder(d->fname); + long firstSector, lastSector; + getSectorsForRequest(drive, firstSector, lastSector); + atom.m_long = fileSize(firstSector, lastSector, encoder); + } + + entry.append(atom); + + statEntry(entry); + + cdda_close(drive); + + finished(); +} + +static void app_entry(UDSEntry& e, unsigned int uds, const TQString& str) +{ + UDSAtom a; + a.m_uds = uds; + a.m_str = str; + e.append(a); +} + +static void app_entry(UDSEntry& e, unsigned int uds, long l) +{ + UDSAtom a; + a.m_uds = uds; + a.m_long = l; + e.append(a); +} + +static void app_dir(UDSEntry& e, const TQString & n, size_t s) +{ + e.clear(); + app_entry(e, TDEIO::UDS_NAME, TQFile::decodeName(n.local8Bit())); + app_entry(e, TDEIO::UDS_FILE_TYPE, S_IFDIR); + app_entry(e, TDEIO::UDS_ACCESS, 0400); + app_entry(e, TDEIO::UDS_SIZE, s); + app_entry(e, TDEIO::UDS_MIME_TYPE, "inode/directory"); +} + +static void app_file(UDSEntry& e, const TQString & n, size_t s) +{ + e.clear(); + app_entry(e, TDEIO::UDS_NAME, TQFile::decodeName(n.local8Bit())); + app_entry(e, TDEIO::UDS_FILE_TYPE, S_IFREG); + app_entry(e, TDEIO::UDS_ACCESS, 0400); + app_entry(e, TDEIO::UDS_SIZE, s); +} + +void AudioCDProtocol::listDir(const KURL & url) +{ + struct cdrom_drive * drive = initRequest(url); + + // Some error checking before proceeding + if (!drive) + return; + + if (d->which_dir == Unknown){ + error(TDEIO::ERR_DOES_NOT_EXIST, url.path()); + cdda_close(drive); + return; + } + + if ( !d->fname.isEmpty() ){ + error(TDEIO::ERR_IS_FILE, url.path()); + cdda_close(drive); + return; + } + + // Generate templated names every time + // because the template might have changed. + generateTemplateTitles(); + + UDSEntry entry; + // If the tracks should be listed in this directory + bool list_tracks = true; + + if (d->which_dir == Info){ + CDInfoList::iterator it; + uint count = 1; + for ( it = d->cddbList.begin(); it != d->cddbList.end(); ++it ){ + (*it).toString(); + if(count == 1) + app_file(entry, TQString("%1.txt").arg(i18n(CDDB_INFORMATION)), ((*it).toString().length())+1); + else + app_file(entry, TQString("%1_%2.txt").arg(i18n(CDDB_INFORMATION)).arg(count), ((*it).toString().length())+1); + count++; + listEntry(entry, false); + } + // Error + if( count == 1 ) { + app_file(entry, TQString("%1: %2.txt").arg(i18n(CDDB_INFORMATION)).arg(CDDB::resultToString(d->cddbResult)), ((*it).toString().length())+1); + count++; + listEntry(entry, false); + } + + list_tracks = false; + } + + if (d->which_dir == Root){ + // List virtual directories. + app_dir(entry, d->s_fullCD, encoders.count()); + listEntry(entry, false); + + // Either >0 cddb results or cddb error file + app_dir(entry, d->s_info, d->cddbList.count()); + listEntry(entry, false); + + // List the encoders + AudioCDEncoder *encoder; + for ( encoder = encoders.first(); encoder; encoder = encoders.next() ){ + // Skip the directory that is in the root (you can still go in it, just don't show it) + if( encoder == encoderTypeWAV ) + continue; + app_dir(entry, encoder->type(), d->tracks); + listEntry(entry, false); + } + } + + // Now fill in the tracks for the current directory + if (list_tracks && d->which_dir == FullCD) { + // if we're listing the "full CD" subdirectory : + if ( (d->which_dir == FullCD) ) { + AudioCDEncoder *encoder; + for ( encoder = encoders.first(); encoder; encoder = encoders.next() ){ + if (d->cddbResult != KCDDB::CDDB::Success) + addEntry(d->s_fullCD, encoder, drive, -1); + else + addEntry(d->templateAlbumName, encoder, drive, -1); + } + } + } + + if (list_tracks && d->which_dir != FullCD) { + // listing another dir than the "FullCD" one. + for (uint trackNumber = 1; trackNumber <= d->tracks; trackNumber++) + { + // Skip data tracks + if (!d->trackIsAudio[trackNumber-1]) + continue; + + switch (d->which_dir) { + case Root:{ + addEntry(d->templateTitles[trackNumber - 1], + encoderTypeWAV, drive, trackNumber); + break; + } + case EncoderDir: + addEntry(d->templateTitles[trackNumber - 1], + d->encoder_dir_type, drive, trackNumber); + break; + case Info: + case Unknown: + default: + error(TDEIO::ERR_INTERNAL, url.path()); + cdda_close(drive); + return; + } + } + } + + totalSize(entry.count()); + listEntry(entry, true); + cdda_close(drive); + finished(); +} + +void AudioCDProtocol::addEntry(const TQString& trackTitle, AudioCDEncoder *encoder, struct cdrom_drive * drive, int trackNo) +{ + if(!encoder || !drive) + return; + + long theFileSize = 0; + if (trackNo == -1) + { // adding entry for the full CD + theFileSize = fileSize(cdda_track_firstsector(drive, 1), + cdda_track_lastsector(drive, cdda_tracks(drive)), + encoder); + } + else + { // adding one regular track + long firstSector = cdda_track_firstsector(drive, trackNo); + long lastSector = cdda_track_lastsector(drive, trackNo); + theFileSize = fileSize(firstSector, lastSector, encoder); + } + UDSEntry entry; + app_file(entry, trackTitle + TQString(".")+encoder->fileType(), theFileSize); + listEntry(entry, false); +} + +long AudioCDProtocol::fileSize(long firstSector, long lastSector, AudioCDEncoder *encoder) +{ + if(!encoder) + return 0; + + long filesize = CD_FRAMESIZE_RAW * ( lastSector - firstSector + 1 ); + long length_seconds = (filesize) / 176400; + + return encoder->size(length_seconds); +} + +struct cdrom_drive *AudioCDProtocol::getDrive() +{ + TQCString device(TQFile::encodeName(d->device)); + + struct cdrom_drive * drive = 0; + + if (!device.isEmpty() && device != "/") + drive = cdda_identify(device, CDDA_MESSAGE_PRINTIT, 0); + else + { + drive = cdda_find_a_cdrom(CDDA_MESSAGE_PRINTIT, 0); + + if (0 == drive) + { + if (TQFile(TQFile::decodeName(DEFAULT_CD_DEVICE)).exists()) + drive = cdda_identify(DEFAULT_CD_DEVICE, CDDA_MESSAGE_PRINTIT, 0); + } + } + + if (0 == drive) { + kdDebug(7117) << "Can't find an audio CD on: \"" << d->device << "\"" << endl; + + TQFileInfo fi(d->device); + if(!fi.isReadable()) + error(TDEIO::ERR_SLAVE_DEFINED, i18n("Device doesn't have read permissions for this account. Check the read permissions on the device.")); + else if(!fi.isWritable()) + error(TDEIO::ERR_SLAVE_DEFINED, i18n("Device doesn't have write permissions for this account. Check the write permissions on the device.")); + else if(!fi.exists()) + error(TDEIO::ERR_DOES_NOT_EXIST, d->device); + else error(TDEIO::ERR_SLAVE_DEFINED, +i18n("Unknown error. If you have a cd in the drive try running cdparanoia -vsQ as yourself (not root). Do you see a track list? If not, make sure you have permission to access the CD device. If you are using SCSI emulation (possible if you have an IDE CD writer) then make sure you check that you have read and write permissions on the generic SCSI device, which is probably /dev/sg0, /dev/sg1, etc.. If it still does not work, try typing audiocd:/?device=/dev/sg0 (or similar) to tell kio_audiocd which device your CD-ROM is.")); + return 0; + } + + if (0 != cdda_open(drive)) + { + kdDebug(7117) << "cdda_open failed" << endl; + error(TDEIO::ERR_CANNOT_OPEN_FOR_READING, d->device); + cdda_close(drive); + return 0; + } + + return drive; +} + +void AudioCDProtocol::paranoiaRead( + struct cdrom_drive * drive, + long firstSector, + long lastSector, + AudioCDEncoder* encoder, + const TQString& fileName, + unsigned long size + ) +{ + if(!encoder || !drive) + return; + + cdrom_paranoia * paranoia = paranoia_init(drive); + if (0 == paranoia) { + kdDebug(7117) << "paranoia_init failed" << endl; + return; + } + + int paranoiaLevel = PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP; + switch (d->paranoiaLevel) + { + case 0: + paranoiaLevel = PARANOIA_MODE_DISABLE; + break; + + case 1: + paranoiaLevel |= PARANOIA_MODE_OVERLAP; + paranoiaLevel &= ~PARANOIA_MODE_VERIFY; + break; + + case 2: + paranoiaLevel |= PARANOIA_MODE_NEVERSKIP; + default: + break; + } + + paranoia_modeset(paranoia, paranoiaLevel); + + cdda_verbose_set(drive, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT); + + paranoia_seek(paranoia, firstSector, SEEK_SET); + + long currentSector(firstSector); + + unsigned long processed = encoder->readInit(CD_FRAMESIZE_RAW * (lastSector - firstSector + 1)); + // TODO test for errors (processed<0)? + processedSize(processed); + bool ok = true; + + unsigned long lastSize = size; + unsigned long diff = 0; + + paranoia_read_limited_error = 0; + int warned = 0; + while (currentSector <= lastSector) + { + // TODO make the 5 configurable? The default in the lib is 20 fyi + int16_t * buf = paranoia_read_limited(paranoia, paranoiaCallback, 5); + if( warned == 0 && paranoia_read_limited_error >= 5 && d->reportErrors ){ + warning(i18n("AudioCD: Disk damage detected on this track, risk of data corruption.")); + warned = 1; + } + if (0 == buf) { + kdDebug(7117) << "Unrecoverable error in paranoia_read" << endl; + ok = false; + error( ERR_SLAVE_DEFINED, i18n( "Error reading audio data for %1 from the CD" ).arg( fileName ) ); + break; + } + + ++currentSector; + + int encoderProcessed = encoder->read(buf, CD_FRAMESAMPLES); + if(encoderProcessed == -1){ + kdDebug(7117) << "Encoder processing error, stopping." << endl; + ok = false; + TQString errMsg = i18n( "Couldn't read %1: encoding failed" ).arg( fileName ); + TQString details = encoder->lastErrorMessage(); + if ( !details.isEmpty() ) + errMsg += "\n" + details; + error( ERR_SLAVE_DEFINED, errMsg ); + break; + } + processed += encoderProcessed; + + /** + * Because compression size is so 'unknown' use some guesswork + * + * 1) First assume that the reported size is correct and + * only change the totalSize if the guess it outside a range of %5. + * 2) Only increase in size unless the decrease is %5 of last estimate. + * This prevents continues small changes which is just annoying. + */ + unsigned long end = lastSector - firstSector; + unsigned long cur = currentSector - firstSector; + unsigned long estSize = (processed / cur ) * end; + + // If our guess is within 5% of reported + // size then use the reported size. + unsigned long guess = (long)((100/(float)size)*estSize); + if((guess > 97 && guess < 103) || estSize == 0){ + if(processed > lastSize){ + totalSize(processed+1); + lastSize = processed; + } + } + else{ + float percentDone = ((float)cur/(float)end); + // Calculate estimated amount that will be wrong + diff = estSize - lastSize; + diff = (diff*(unsigned long)((100/(float)end)*(end-cur)))/2; + // Need 1% of data calculated as initial buffer, use %2 to be safe + if( percentDone < .02 ){ + //tqDebug("val: %f, diff: %ld", ((float)cur/(float)end), diff); + diff = 0; + } + + // We are growing larger, increase total. + if(lastSize < estSize){ + //tqDebug("lastGuess: %ld, guess: %ld diff: %ld", lastSize, estSize, diff); + totalSize(estSize+diff); + lastSize = estSize+diff; + } + else{ + int margin = (int)((percentDone)*75); + // Don't bother really trying until almost half way done. + if( percentDone <= .40 ) + margin = 7; + unsigned long low = lastSize - lastSize/margin; + if(estSize < low){ + //tqDebug("low: %ld, estSize: %ld, num: %i", low, estSize, margin); + totalSize( estSize ); + lastSize = estSize; + } + } + } + /** + * End estimation. + */ + //tqDebug("processed: %ld, totalSize: %ld", processed, estSize); + processedSize(processed); + } + + if(processed > size) + totalSize(processed); + + long encoderProcessed = encoder->readCleanup(); + if ( encoderProcessed >= 0 ) { + processed += encoderProcessed; + if(processed > size) + totalSize(processed); + processedSize(processed); + } + else if ( ok ) // i.e. no error message already emitted + error( ERR_SLAVE_DEFINED, i18n( "Couldn't read %1: encoding failed" ).arg( fileName ) ); + + paranoia_free(paranoia); + paranoia = 0; +} + +/** + * Read the settings from the URL + * @see loadSettings() + */ +void AudioCDProtocol::parseURLArgs(const KURL & url) +{ + d->clearURLargs(); + + TQString query(KURL::decode_string(url.query())); + + if (query.isEmpty() || query[0] != '?') + return; + + query = query.mid(1); // Strip leading '?'. + + TQStringList tokens(TQStringList::split('&', query)); + + for (TQStringList::ConstIterator it(tokens.begin()); it != tokens.end(); ++it) + { + TQString token(*it); + + int equalsPos(token.find('=')); + if (-1 == equalsPos) + continue; + + TQString attribute(token.left(equalsPos)); + TQString value(token.mid(equalsPos + 1)); + + if (attribute == TQFL1("device")) + d->device = value; + else if (attribute == TQFL1("paranoia_level")) + d->paranoiaLevel = value.toInt(); + else if (attribute == TQFL1("fileNameTemplate")) + d->fileNameTemplate = value; + else if (attribute == TQFL1("albumNameTemplate")) + d->albumTemplate = value; + else if (attribute == TQFL1("cddbChoice")) + d->cddbUserChoice = value.toInt(); + else if (attribute == TQFL1("niceLevel")){ + int niceLevel = value.toInt(); + if(setpriority(PRIO_PROCESS, getpid(), niceLevel) != 0) + kdDebug(7117) << "Setting nice level to (" << niceLevel << ") failed." << endl; + } + } +} + +/** + * Read the settings set by the kcm modules + * @see parseURLArgs() + */ +void AudioCDProtocol::loadSettings() +{ + TDEConfig *config = new TDEConfig(TQFL1("kcmaudiocdrc"), true /*readonly*/, false /*no kdeglobals*/); + + config->setGroup(TQFL1("CDDA")); + + if (!config->readBoolEntry(TQFL1("autosearch"),true)) { + d->device = config->readEntry(TQFL1("device"),TQFL1(DEFAULT_CD_DEVICE)); + } + + d->paranoiaLevel = 1; // enable paranoia error correction, but allow skipping + + if (config->readBoolEntry("disable_paranoia",false)) { + d->paranoiaLevel = 0; // disable all paranoia error correction + } + + if (config->readBoolEntry("never_skip",true)) { + d->paranoiaLevel = 2; + // never skip on errors of the medium, should be default for high quality + } + + d->reportErrors = config->readBoolEntry( "report_errors", false ); + + if(config->hasKey("niceLevel")) { + int niceLevel = config->readNumEntry("niceLevel", 0); + if(setpriority(PRIO_PROCESS, getpid(), niceLevel) != 0) + kdDebug(7117) << "Setting nice level to (" << niceLevel << ") failed." << endl; + } + + // The default track filename template + config->setGroup("FileName"); + d->fileNameTemplate = config->readEntry("file_name_template", "%{albumartist} - %{number} - %{title}"); + d->albumTemplate = config->readEntry("album_template", "%{albumartist} - %{albumtitle}"); + d->rsearch = config->readEntry("regexp_search"); + d->rreplace = config->readEntry("regexp_replace"); + // if the regular expressions are enclosed in qoutes. remove them + // otherwise it is not possible to search for a space " ", since an empty (only spaces) value is not + // supported by TDEConfig, so the space has to be qouted, but then here the regexp searches really for " " + // instead of just the space. Alex + TQRegExp qoutedString("^\".*\"$"); + if (qoutedString.exactMatch(d->rsearch)) + { + d->rsearch=d->rsearch.mid(1, d->rsearch.length()-2); + } + if (qoutedString.exactMatch(d->rreplace)) + { + d->rreplace=d->rreplace.mid(1, d->rreplace.length()-2); + } + + // Tell the encoders to load their settings + AudioCDEncoder *encoder = encoders.first(); + while ( encoder ) { + if ( encoder->init() ) { + kdDebug(7117) << "Encoder for " << encoder->type() << " is available." << endl; + encoder->loadSettings(); + encoder = encoders.next(); + } else { + kdDebug(7117) << "Encoder for " << encoder->type() << " is NOT available." << endl; + encoders.remove( encoder ); + encoder = encoders.current(); + } + } + + delete config; +} + +/** + * Generates the track titles from the template using the cddb information. + */ +void AudioCDProtocol::generateTemplateTitles() +{ + d->templateTitles.clear(); + if (d->cddbResult != KCDDB::CDDB::Success) + { + for (unsigned int i = 0; i < d->tracks; i++){ + TQString n; + d->templateTitles.append( i18n("Track %1").arg(n.sprintf("%02d", i + 1))); + } + return; + } + + KCDDB::CDInfo info = d->cddbBestChoice; + if(d->cddbUserChoice >= 0 && (((uint)d->cddbUserChoice) < d->cddbList.count())) + info = d->cddbList[d->cddbUserChoice]; + + // Then generate the templates + d->templateTitles.clear(); + for (uint i = 0; i < d->tracks; i++) { + TQMap<TQString, TQString> macros; + macros["albumartist"] = info.artist; + macros["albumtitle"] = info.title; + macros["title"] = (info.trackInfoList[i].title); + TQString n; + macros["number"] = n.sprintf("%02d", i + 1); + //macros["number"] = TQString("%1").arg(i+1, 2, 10); + macros["genre"] = info.genre; + macros["year"] = TQString::number(info.year); + + TQString title = KMacroExpander::expandMacros(d->fileNameTemplate, macros, '%').replace('/', TQFL1("%2F")); + title.replace( TQRegExp(d->rsearch), d->rreplace ); + d->templateTitles.append(title); + } + + TQMap<TQString, TQString> macros; + macros["albumartist"] = info.artist; + macros["albumtitle"] = info.title; + macros["genre"] = info.genre; + macros["year"] = TQString::number(info.year); + d->templateAlbumName = KMacroExpander::expandMacros(d->albumTemplate, macros, '%').replace('/', TQFL1("%2F")); + d->templateAlbumName.replace( TQRegExp(d->rsearch), d->rreplace ); +} + +/** + * Based upon the cdparinoia ripping application + * Only output BAD stuff + * The higher the paranoia_read_limited_error the worse the problem is + * FYI: PARANOIA_CB_READ & PARANOIA_CB_VERIFY happen continusly when ripping + */ +void paranoiaCallback(long, int function) +{ + switch(function){ + case PARANOIA_CB_VERIFY: + //kdDebug(7117) << "PARANOIA_CB_VERIFY" << endl; + break; + + case PARANOIA_CB_READ: + //kdDebug(7117) << "PARANOIA_CB_READ" << endl; + break; + + case PARANOIA_CB_FIXUP_EDGE: + //kdDebug(7117) << "PARANOIA_CB_FIXUP_EDGE" << endl; + paranoia_read_limited_error = 2; + break; + + case PARANOIA_CB_FIXUP_ATOM: + //kdDebug(7117) << "PARANOIA_CB_FIXUP_ATOM" << endl; + paranoia_read_limited_error = 6; + break; + + case PARANOIA_CB_READERR: + kdDebug(7117) << "PARANOIA_CB_READERR" << endl; + paranoia_read_limited_error = 6; + break; + + case PARANOIA_CB_SKIP: + kdDebug(7117) << "PARANOIA_CB_SKIP" << endl; + paranoia_read_limited_error = 8; + break; + + case PARANOIA_CB_OVERLAP: + //kdDebug(7117) << "PARANOIA_CB_OVERLAP" << endl; + break; + + case PARANOIA_CB_SCRATCH: + kdDebug(7117) << "PARANOIA_CB_SCRATCH" << endl; + paranoia_read_limited_error = 7; + break; + + case PARANOIA_CB_DRIFT: + //kdDebug(7117) << "PARANOIA_CB_DRIFT" << endl; + paranoia_read_limited_error = 4; + break; + + case PARANOIA_CB_FIXUP_DROPPED: + kdDebug(7117) << "PARANOIA_CB_FIXUP_DROPPED" << endl; + paranoia_read_limited_error = 5; + break; + + case PARANOIA_CB_FIXUP_DUPED: + kdDebug(7117) << "PARANOIA_CB_FIXUP_DUPED" << endl; + paranoia_read_limited_error = 5; + break; + } +} + diff --git a/tdeioslave/audiocd/audiocd.h b/tdeioslave/audiocd/audiocd.h new file mode 100644 index 00000000..75b9bfd2 --- /dev/null +++ b/tdeioslave/audiocd/audiocd.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + * Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + * Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + * Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + * Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + * Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + * Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + * + * 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 + * ERCHANTABILITY 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef AUDIO_CD_H +#define AUDIO_CD_H + +#include <tdeio/slavebase.h> + +class AudioCDEncoder; + +struct cdrom_drive; + +namespace AudioCD { + +/** + * The core class of the audiocd:// ioslave. + * It has the iosalve login and the ripping logic. The actual encoding + * is done by encoders that are seperate objects. + */ +class AudioCDProtocol : public TDEIO::SlaveBase +{ + public: + + AudioCDProtocol(const TQCString & protocol, const TQCString & pool, const TQCString & app); + virtual ~AudioCDProtocol(); + + virtual void get(const KURL &); + virtual void stat(const KURL &); + virtual void listDir(const KURL &); + + protected: + AudioCDEncoder *encoderFromExtension(const TQString& extension); + AudioCDEncoder *determineEncoder(const TQString & filename); + + struct cdrom_drive *findDrive(bool &noPermission); + void parseURLArgs(const KURL &); + + void loadSettings(); + + /** + * From the request information (Private member "d"), + * get the first and last sector for the request. + * return false if the parameters are invalid (for instance, + * track number which does not exist on this CD) + */ + bool getSectorsForRequest(struct cdrom_drive * drive, + long & firstSector, long & lastSector) const; + + /** + * Give the size in bytes of the space between those two + * sectors, depending on the file type. + */ + long fileSize(long firstSector, long lastSector, AudioCDEncoder *encoder); + + /** + * The heart of this ioslave. + * Reads data off the cd and then passes it to an encoder to encode + */ + void paranoiaRead( + struct cdrom_drive * drive, + long firstSector, + long lastSector, + AudioCDEncoder* encoder, + const TQString& fileName, + unsigned long size + ); + + struct cdrom_drive *initRequest(const KURL &); + uint discid(struct cdrom_drive *); + + /** + * Add an entry in the KIO directory, using the title you give, + * it will set the extension itself depending on the fileType. + * You must also give the trackNumber for the size of the file + * to be calculated. + * NOTE: if you want to add a file which is the whole CD, give + * trackNo = -1 + * NOTE2: you can safely add MP3 or OGG files always. the function + * will check if kio_audiocd was compiled with support for those, + * so NO NEED to wrap your calls with #ifdef for lame or vorbis. + * this function will do the right thing. + */ + void addEntry(const TQString& trackTitle, AudioCDEncoder *encoder, + struct cdrom_drive * drive, int trackNo); + + class Private; + Private * d; + +private: + + void generateTemplateTitles(); + + TQPtrList<AudioCDEncoder> encoders; + cdrom_drive * getDrive(); + + // These are the only garenteed encoders to be built, the rest + // are dynamic depending on other libraries on the system + AudioCDEncoder *encoderTypeCDA; + AudioCDEncoder *encoderTypeWAV; +}; + +} // end namespace AudioCD + +#endif // AUDIO_CD_H + diff --git a/tdeioslave/audiocd/audiocd.protocol b/tdeioslave/audiocd/audiocd.protocol new file mode 100644 index 00000000..eb462539 --- /dev/null +++ b/tdeioslave/audiocd/audiocd.protocol @@ -0,0 +1,16 @@ +[Protocol] +exec=kio_audiocd +protocol=audiocd +input=none +output=filesystem +listing=Name,Type,Size,Access +reading=true +writing=false +makedir=false +deleting=false +linking=false +moving=false +Icon=cdaudio_unmount +DocPath=tdeioslave/audiocd.html +Class=:local +ShowPreviews=false diff --git a/tdeioslave/audiocd/audiocd.upd b/tdeioslave/audiocd/audiocd.upd new file mode 100644 index 00000000..f4818e5f --- /dev/null +++ b/tdeioslave/audiocd/audiocd.upd @@ -0,0 +1,4 @@ +# Update for transport configuration +Id=1 +File=kcmaudiocdrc +Script=upgrade-metadata.sh,bash diff --git a/tdeioslave/audiocd/configure.in.bot b/tdeioslave/audiocd/configure.in.bot new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tdeioslave/audiocd/configure.in.bot diff --git a/tdeioslave/audiocd/configure.in.in b/tdeioslave/audiocd/configure.in.in new file mode 100644 index 00000000..99bacf59 --- /dev/null +++ b/tdeioslave/audiocd/configure.in.in @@ -0,0 +1,46 @@ +AC_DEFUN([AC_CHECK_LIBFLAC], +[ + AC_LANG_SAVE + AC_LANG_C + have_libFLAC=no + KDE_CHECK_HEADER(FLAC/metadata.h, + [ + KDE_CHECK_LIB(FLAC,FLAC__stream_decoder_process_single, + have_libFLAC=yes) + + ]) + if test "x$have_libFLAC" = "xyes"; then + LIBFLAC="-lFLAC" + AC_DEFINE(HAVE_LIBFLAC, 1, + [Define if you have libFLAC (required for loading FLAC files)]) + fi + AC_SUBST(LIBFLAC) + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_CHECK_LIBOGGFLAC], +[ + AC_LANG_SAVE + AC_LANG_C + have_libOggFLAC=no + KDE_CHECK_HEADER(OggFLAC/seekable_stream_decoder.h, + [ + KDE_CHECK_LIB(OggFLAC,OggFLAC__seekable_stream_decoder_process_single, + have_libOggFLAC=yes,,[-lm -lOggFLAC -lFLAC]) + + ]) + if test "x$have_libOggFLAC" = "xyes"; then + LIBOGGFLAC="-lOggFLAC" + AC_DEFINE(HAVE_LIBOGGFLAC, 1, + [Define if you have libOggFLAC (required for loading OggFLAC files)]) + fi + AC_SUBST(LIBOGGFLAC) + AC_LANG_RESTORE +]) + +AC_ARG_WITH(flac,AC_HELP_STRING([--with-flac],[Enable FLAC support @<:@default=check@:>@]),[flac_test="$withval"],[flac_test="yes"]) + +if test "x$flac_test" = "xyes" ; then + AC_CHECK_LIBFLAC + AC_CHECK_LIBOGGFLAC +fi diff --git a/tdeioslave/audiocd/kcmaudiocd/Makefile.am b/tdeioslave/audiocd/kcmaudiocd/Makefile.am new file mode 100644 index 00000000..73d6be2d --- /dev/null +++ b/tdeioslave/audiocd/kcmaudiocd/Makefile.am @@ -0,0 +1,17 @@ +kde_module_LTLIBRARIES = kcm_audiocd.la + +kcm_audiocd_la_SOURCES = audiocdconfig.ui kcmaudiocd.cpp + +kcm_audiocd_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +kcm_audiocd_la_LIBADD = ../plugins/libaudiocdplugins.la $(LIB_TDEUI) + +INCLUDES = -I$(srcdir)/../plugins -I$(top_srcdir)/libkcddb $(all_includes) + +kcm_audiocd_la_METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kcmaudiocd.pot + +xdg_apps_DATA = audiocd.desktop + +audiocdconfig.cpp: audiocdconfig.h diff --git a/tdeioslave/audiocd/kcmaudiocd/audiocd.desktop b/tdeioslave/audiocd/kcmaudiocd/audiocd.desktop new file mode 100644 index 00000000..88bfedde --- /dev/null +++ b/tdeioslave/audiocd/kcmaudiocd/audiocd.desktop @@ -0,0 +1,182 @@ +[Desktop Entry] +Exec=tdecmshell audiocd +Icon=cdaudio_unmount +Type=Application + +X-TDE-ModuleType=Library +X-TDE-Library=audiocd + +Name=Audio CDs +Name[af]=Audio Cds +Name[ar]=أقراص مدمجة صوتية +Name[bg]=Аудио диск +Name[bn]=অডিও সিডি +Name[br]=CD klevet +Name[bs]=Audio CDi +Name[ca]=CD d'àudio +Name[cs]=Zvuková CD +Name[cy]=CDau Sain +Name[da]=Lyd-cd'er +Name[de]=Audio-CDs +Name[el]=CD μουσικής +Name[eo]=Son-KDoj +Name[es]=CDs audio +Name[et]=Audioplaadid +Name[eu]=Audio CD-ak +Name[fa]=دیسکهای فشردۀ صوتی +Name[fi]=Ääni-CD:t +Name[fr]=CD audio +Name[ga]=Dlúthdhioscaí Fuaime +Name[he]=תקליטורי שמע +Name[hi]=ऑडीयो सीडी +Name[hr]=Audio CD-i +Name[hu]=Hang-CD-böngésző +Name[is]=Tónlistardiskaflakkari +Name[it]=CD Audio +Name[ja]=オーディオ CD +Name[kk]=Аудио CD +Name[km]=ស៊ីឌីអ៉ូឌីយ៉ូ +Name[ko]=오디오 CD +Name[lt]=Audio kompaktai +Name[mk]=Аудио ЦД-а +Name[nb]=Lyd-CD-er +Name[nds]=Klang-CDs +Name[ne]=अडियो सीडी +Name[nl]=Audio-cd's +Name[nn]=Lyd-CD-ar +Name[pa]=ਆਡੀਓ CD +Name[pl]=Przeglądarka audio CD +Name[pt]=CDs de Áudio +Name[pt_BR]=CDs de Áudio +Name[ro]=CD-uri audio +Name[ru]=Аудио CD +Name[se]=Jietna-CD:at +Name[sk]=Zvukové CD +Name[sl]=Avdio CD-ji +Name[sr]=Аудио CD-ови +Name[sr@Latn]=Audio CD-ovi +Name[sv]=Ljud-cd +Name[ta]=கேட்பொலி குறுந்தகடுகள் +Name[tg]=Дискҳои Фишурдаи Садо +Name[th]=ซีดีบันทึกเสียง +Name[tr]=Müzik CD +Name[uk]=Аудіо-КД +Name[uz]=Audio kompakt-disklar +Name[uz@cyrillic]=Аудио компакт-дисклар +Name[ven]=CD ino thetsheleswa +Name[xh]=CDs Zokuvakalayo +Name[zh_CN]=音频 CD +Name[zh_HK]=音樂 CD +Name[zh_TW]=音樂光碟 +Name[zu]=Ama-CD Okuzwakalayo +Comment=Audiocd IO Slave Configuration +Comment[af]=Klank cd Io Slaaf Opstelling +Comment[az]=Name=Audiosd IO Kölələri Quraşdırması +Comment[bg]=Настройване на аудио диска +Comment[bn]=অডিও-সিডি আই/ও স্লেভ কনফিগারেশন +Comment[br]=Kefluniadur Sklav IO Audiocd +Comment[bs]=Podešavanje Audiocd IO Slave +Comment[ca]=Configuració de l'E/S esclava dels CD àudio +Comment[cs]=Nastavení IO klienta pro zvuková CD +Comment[cy]=Gosodiad Gwas IO ar gyfer CDau Sain +Comment[da]=Lyd-cd IO-slave-indstilling +Comment[de]=Einrichtung des Ein-/Ausgabemoduls für Audio-CDs +Comment[el]=Ρύθμιση Audiocd IO Slave +Comment[eo]=Agordo por la muzikdiska sklavo +Comment[es]=Configuración del esclavo de E/S de audiocd +Comment[et]=Audio CD IO mooduli seadistamine +Comment[eu]=Audiocd IO mendekoaren konfigurazioa +Comment[fa]=پیکربندی پیرو IO دیسک فشردۀ صوتی +Comment[fi]=Audiocd-siirräntätyöskentelijän asetukset +Comment[fr]=Configuration du module pour CD audio +Comment[gl]=Configuración do escravo IO de audiocd +Comment[he]=שינוי הגדרות פרוטוקול תקליטורי השמע +Comment[hi]=ऑडियो-सीडी आई-ओ स्लेव कॉन्फ़िगरेशन +Comment[hr]=Postava Audiocd IO poslužnika +Comment[hu]=Az audiocd TDE-protokoll beállításai +Comment[is]=Stillingar Audiocd I/O þrælsins +Comment[it]=Configurazione dell'IO Slave per i CD Audio +Comment[ja]=オーディオ CD IO スレーブの設定 +Comment[kk]=AudioCD IO Slave баптауы +Comment[km]=ការកំណត់រចនាសម្ព័ន្ធ IO Slave របស់ស៊ីឌីអូឌីយ៉ូ +Comment[ko]=오디오 CD IO 슬레이브 설정 +Comment[lt]=Audio kompakto IO vergo derinimas +Comment[ms]=Penyelarasan Hamba IO Audiocd +Comment[mt]=Konfigurazzjoni tal-iskjav IO AudioCD +Comment[nb]=Oppsett av lyd-CD IO-slave +Comment[nds]=Instellen för dat In-/Utgaavmoduul för Klang-CDs +Comment[ne]=Audiocd IO स्लेभ कन्फिगरेसन +Comment[nl]=AudioCD IO slave instellen +Comment[nn]=Oppsett av IU-slave for lyd-CD +Comment[pa]=ਆਡੀਓ ਸੀਡੀ IO ਸਲੇਵ ਸੰਰਚਨਾ +Comment[pl]=Konfiguracja procedury we/wy dla audio CD +Comment[pt]=Configuração do IO Slave de CDs-Áudio +Comment[pt_BR]=Configuração do Áudio CD Escravo +Comment[ro]=Configurează dispozitivul I/O pentru CD audio +Comment[ru]=Настройка протокола AudioCD +Comment[se]=Heivet SO-šláva jietna-CD:aid várás +Comment[sk]=Nastavenie IO klienta pre zvukové CD +Comment[sl]=Nastavitve Audiocd podrejeni V/I +Comment[sr]=Подешавање Audiocd IO Slave-а +Comment[sr@Latn]=Podešavanje Audiocd IO Slave-a +Comment[sv]=Anpassa I/O-slav för ljud-cd +Comment[ta]=ஒலிக் குறுந்தகடு உள்-வெளி அடிமை வடிவமைப்பு +Comment[tg]=Танзими Фармонбари Ворид/Хориҷи Дискҳои Фишурдаи Садо +Comment[th]=ปรับแต่ง Audiocd IO Slave +Comment[tr]=Müzik CD Yapılandırması +Comment[uk]=Налаштування підлеглого В/В "Audiocd" +Comment[ven]=Nzudzanyo Audiocd IO Slave +Comment[xh]=Video-DVD IO Slave Uqwalaselo +Comment[zh_CN]=音频 CD 输入输出从属模块配置 +Comment[zh_HK]=音樂 CD IO Slave 設定 +Comment[zh_TW]=音樂光碟 IO Slave 組態 +Comment[zu]=Inhlanganiselo ye-Audiocd IO Slave +Keywords=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate +Keywords[bg]=аудио, диск, компактдиск, КД, кодек, музика, Audio CD, CD, Ogg, Vorbis, Encoding, CDDA, Bitrate +Keywords[br]=CD klevet,CD,Ogg,Vorbis,Kodadur,CDDA,Feur +Keywords[ca]=Àudio CD,CD,Ogg,Vorbis,Codificació,CDDA,Taxa de bits +Keywords[cs]=Zvukové CD,CD,Ogg,Vorbis,Kódování,CDDA,Bitrate,CDDB +Keywords[cy]=CD Sain,CD,crynoddisg,Ogg,Vorbis,Amgodio,CDDA,Cyfradd Ddidau +Keywords[da]=Lyd-cd,CD,Ogg,Vorbis,Indkodning,CDDA,Bitrate +Keywords[de]=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate,MP3 +Keywords[el]=CD μουσικής,CD,Ogg,Vorbis,Κωδικοποίηση,CDDA,Ρυθμός bit +Keywords[es]=CD de audio,CD,Ogg,Vorbis,Codificación,CDDA,Ratio de bits +Keywords[et]=audio,CD,Ogg,Vorbis,kodeering,CDDA,bitikiirus +Keywords[eu]=Audio CD,CD,Ogg,Vorbis,Kdeketa,CDDA,bit-maiztasuna +Keywords[fa]=دیسک فشرده، دیسک فشرده، Ogg، Vorbis، کدبندی، CDDA، میزان ارسال بیت صوتی +Keywords[fi]=Ääni-CD,CD,Ogg,Vorbis,Koodaus,CDDA,Bittinopeus +Keywords[fr]=CD audio,CD,Ogg,Vorbis,Encodage,CDDA,débit +Keywords[ga]=CD Fuaime,CD,Ogg,Vorbis,Ionchódú,CDDA,Ráta Giotán +Keywords[gl]=Audio CD,CD,Ogg,Vorbis,Codificación,CDDA,Razón de Bits +Keywords[hi]=ऑडियो सीडी,सीडी,ऑग,वॉर्बिस,एनकोडिंग,सीडीडीए,बिटरेट +Keywords[hu]=hang-CD,CD,Ogg,Vorbis,kódolás,CDDA,bitráta +Keywords[it]=CD Audio,CD,Ogg,Vorbis,Codifica,CDDA,Bitrate +Keywords[ja]=オーディオ CD,CD,Ogg,Vorbis,エンコーディング,CDDA,ビットレート +Keywords[km]=ស៊ីឌីអូឌីយ៉ូ,ស៊ីឌី,Ogg,Vorbis,អ៊ិនកូដ,CDDA,អត្រាប៊ីត +Keywords[ko]=오디오 CD,CD,Ogg,인코딩,CDDA +Keywords[lt]=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate,įkodavimas +Keywords[mk]=Аудио CD,CD,Ogg,Vorbis,Кодирање,CDDA,Брзина во битови +Keywords[nb]=Audio CD,CD,Ogg,Vorbis,Koding,CDDA,Bitrate +Keywords[nds]=Audio-CD,Klang-CD,CD,Ogg,Vorbis,Koderen,CDDA,Bitrate +Keywords[ne]=अडियो सीडी,सीडी,अग,भर्बिस,सङ्केतन,सीडीडीए,बिटरेट +Keywords[nl]=Audio-cd,cd,Ogg,Vorbis,Encoding,CDDA,Bitrate +Keywords[nn]=lyd-CD,CD,Ogg,Vorbis,koding,CDDA,bitrate +Keywords[pa]=ਆਡੀਓ CD,CD,Ogg,Vorbis,ਇਕੋਡਿੰਗ,CDDA,ਬਿੱਟਰੇਟ +Keywords[pl]=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate, Kodowanie +Keywords[pt]=CD de Áudio,CD,Ogg,Vorbis,Codificação,CDDA,Taxa de Bits +Keywords[pt_BR]=CD de Áudio,CD,Ogg,Vorbis,Codificação,CDDA,Bitrate +Keywords[ro]=CD audio,ogg,vorbis,codare,CDDA,rată de bit +Keywords[ru]=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate,битрейт +Keywords[sk]=zvukové CD,CD,Ogg,Vorbis,kódovanie,CDDA,bitová frekvencia +Keywords[sl]=Avdio CD,CD,Ogg,Vorbis,kodiranje,CDDA,bitna hitrost +Keywords[sr]=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate, Аудио CD, кодирање,битрата +Keywords[sr@Latn]=Audio CD,CD,Ogg,Vorbis,Encoding,CDDA,Bitrate, Audio CD, kodiranje,bitrata +Keywords[sv]=ljud-cd,cd,Ogg,Vorbis,kodning,CDDA,bithastighet +Keywords[ta]=கேட்பொலி குறுந்தகடு,குறுந்தகடு,ஓஜிஜி,வோர்பிஸ்,குறியிடுதல்,சிடிடேஏ,பிட் மதிப்பு +Keywords[tg]=Диски Фишурдаи Садо,Диски Фишурда,Ogg,Vorbis,Рамзигузор,CDDA,Bitrate +Keywords[th]=ซีดีบันทึกเสียง, ซีดี,Ogg,Vorbis,เข้ารหัส,CDDA,บิตเรต +Keywords[tr]=Ses CD,CD,Ogg,Vorbis,Kodlama,CDDA,Bitrate +Keywords[uk]=Аудіо-КД,КД,Ogg,Vorbis,кодування,CDDA,частота вибірки +Keywords[zh_CN]=音频 CD,CD,Ogg,Vorbis,编码,CDDA,Bitrate + +Categories=Qt;TDE;Settings;X-TDE-settings-sound; diff --git a/tdeioslave/audiocd/kcmaudiocd/audiocdconfig.ui b/tdeioslave/audiocd/kcmaudiocd/audiocdconfig.ui new file mode 100644 index 00000000..a3b98507 --- /dev/null +++ b/tdeioslave/audiocd/kcmaudiocd/audiocdconfig.ui @@ -0,0 +1,628 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AudiocdConfig</class> +<widget class="TDECModule"> + <property name="name"> + <cstring>AudiocdConfig</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>563</height> + </rect> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="TQTabWidget"> + <property name="name"> + <cstring>tabWidget</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&General</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="4" column="2"> + <property name="name"> + <cstring>Spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>210</height> + </size> + </property> + </spacer> + <widget class="TQGroupBox" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>encoderPriority</cstring> + </property> + <property name="title"> + <string>Encoder Priority</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQSlider" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>niceLevel</cstring> + </property> + <property name="minValue"> + <number>-19</number> + </property> + <property name="maxValue"> + <number>19</number> + </property> + <property name="lineStep"> + <number>5</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>NoMarks</enum> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Highest</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Lowest</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + </widget> + <widget class="TQLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Normal</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + </grid> + </widget> + <widget class="TQLineEdit" row="0" column="2"> + <property name="name"> + <cstring>cd_device_string</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>/dev/cdrom</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Specify a location for the drive you want to use. Normally, this is a file inside the /dev folder representing your CD or DVD drive.</string> + </property> + </widget> + <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>cd_specify_device</cstring> + </property> + <property name="text"> + <string>&Specify CD device:</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this to specify a CD device different from the one which is detected automatically</string> + </property> + </widget> + <widget class="TQCheckBox" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>ec_enable_check</cstring> + </property> + <property name="text"> + <string>Use &error correction when reading the CD</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>If you uncheck this option, the slave will not try to use error correction which can be useful for reading damaged CDs. However, this feature can be problematic in some cases, so you can switch it off here.</string> + </property> + </widget> + <widget class="TQCheckBox" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>ec_skip_check</cstring> + </property> + <property name="text"> + <string>&Skip on errors</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer4_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Names</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox" row="0" column="0"> + <property name="name"> + <cstring>fileNameGroupBox</cstring> + </property> + <property name="title"> + <string>File Name (without extension)</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>The following macros will be expanded:</string> + </property> + </widget> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="5" column="1"> + <property name="name"> + <cstring>textLabel13</cstring> + </property> + <property name="text"> + <string>Genre</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel7</cstring> + </property> + <property name="text"> + <string>Track Number</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2_3</cstring> + </property> + <property name="text"> + <string>%{title}</string> + </property> + </widget> + <widget class="TQLabel" row="4" column="1"> + <property name="name"> + <cstring>textLabel11</cstring> + </property> + <property name="text"> + <string>Year</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel3_3</cstring> + </property> + <property name="text"> + <string>Track Title</string> + </property> + </widget> + <widget class="TQLabel" row="3" column="1"> + <property name="name"> + <cstring>textLabel9</cstring> + </property> + <property name="text"> + <string>Album Artist</string> + </property> + </widget> + <widget class="TQLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel10</cstring> + </property> + <property name="text"> + <string>%{year}</string> + </property> + </widget> + <widget class="TQLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>%{albumtitle}</string> + </property> + </widget> + <widget class="TQLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>Album Title</string> + </property> + </widget> + <widget class="TQLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel12</cstring> + </property> + <property name="text"> + <string>%{genre}</string> + </property> + </widget> + <widget class="TQLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="text"> + <string>%{albumartist}</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel4_2</cstring> + </property> + <property name="text"> + <string>%{number}</string> + </property> + </widget> + </grid> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>fileNameLineEdit</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="TQGroupBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Name Regular Expression Replacement</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Selection:</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Regular expression used on all file names. For example using selection " " and replace with "_" would replace all the spaces with underlines. +</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="TQLabel" row="5" column="0"> + <property name="name"> + <cstring>inputlabel</cstring> + </property> + <property name="text"> + <string>Input:</string> + </property> + </widget> + <widget class="TQLabel" row="6" column="0"> + <property name="name"> + <cstring>outputLabel</cstring> + </property> + <property name="text"> + <string>Output:</string> + </property> + </widget> + <widget class="TQLabel" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>exampleLabel</cstring> + </property> + <property name="text"> + <string>Example</string> + </property> + </widget> + <widget class="TQLabel" row="6" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>exampleOutput</cstring> + </property> + <property name="text"> + <string>Cool artist - example audio file.wav</string> + </property> + </widget> + <widget class="TQLineEdit" row="5" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>example</cstring> + </property> + <property name="text"> + <string>Cool artist - example audio file.wav</string> + </property> + </widget> + <widget class="TQLineEdit" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kcfg_replaceInput</cstring> + </property> + </widget> + <widget class="TQLineEdit" row="2" column="2"> + <property name="name"> + <cstring>kcfg_replaceOutput</cstring> + </property> + </widget> + <widget class="TQLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="text"> + <string>Replace with:</string> + </property> + </widget> + <widget class="Line" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </grid> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="TQGroupBox" row="0" column="1"> + <property name="name"> + <cstring>fileNameGroupBox_2</cstring> + </property> + <property name="title"> + <string>Album Name</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>fileNameLabel_2</cstring> + </property> + <property name="text"> + <string>The following macros will be expanded:</string> + </property> + </widget> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="2" column="1" rowspan="2" colspan="1"> + <property name="name"> + <cstring>textLabel20</cstring> + </property> + <property name="text"> + <string>Year</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="0" rowspan="2" colspan="1"> + <property name="name"> + <cstring>textLabel15</cstring> + </property> + <property name="text"> + <string>%{albumartist}</string> + </property> + </widget> + <widget class="TQLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel16</cstring> + </property> + <property name="text"> + <string>%{year}</string> + </property> + </widget> + <widget class="TQLabel" row="4" column="1"> + <property name="name"> + <cstring>textLabel21</cstring> + </property> + <property name="text"> + <string>Genre</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel19</cstring> + </property> + <property name="text"> + <string>Album Artist</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel18</cstring> + </property> + <property name="text"> + <string>Album Title</string> + </property> + </widget> + <widget class="TQLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel17</cstring> + </property> + <property name="text"> + <string>%{genre}</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel14</cstring> + </property> + <property name="text"> + <string>%{albumtitle}</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="KLineEdit"> + <property name="name"> + <cstring>albumNameLineEdit</cstring> + </property> + </widget> + </vbox> + </widget> + </grid> + </widget> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>ec_enable_check</sender> + <signal>toggled(bool)</signal> + <receiver>ec_skip_check</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>cd_specify_device</sender> + <signal>toggled(bool)</signal> + <receiver>cd_device_string</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>tabWidget</tabstop> + <tabstop>cd_device_string</tabstop> + <tabstop>ec_enable_check</tabstop> + <tabstop>ec_skip_check</tabstop> + <tabstop>niceLevel</tabstop> + <tabstop>fileNameLineEdit</tabstop> + <tabstop>albumNameLineEdit</tabstop> + <tabstop>kcfg_replaceInput</tabstop> + <tabstop>kcfg_replaceOutput</tabstop> + <tabstop>example</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">tdecmodule.h</include> +</includes> +<Q_SLOTS> + <slot>toggleLowpass()</slot> +</Q_SLOTS> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/tdeioslave/audiocd/kcmaudiocd/kcmaudiocd.cpp b/tdeioslave/audiocd/kcmaudiocd/kcmaudiocd.cpp new file mode 100644 index 00000000..f3190d43 --- /dev/null +++ b/tdeioslave/audiocd/kcmaudiocd/kcmaudiocd.cpp @@ -0,0 +1,267 @@ +/* + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <tdeconfig.h> +#include <klineedit.h> +#include <klocale.h> + +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqgroupbox.h> +#include <tqslider.h> +#include <tqtabwidget.h> +#include <kaboutdata.h> +#include <knuminput.h> +#include <tqregexp.h> +#include <tqlabel.h> + +#include <audiocdencoder.h> +#include "kcmaudiocd.moc" +#include <tdeconfigdialogmanager.h> + +KAudiocdModule::KAudiocdModule(TQWidget *parent, const char *name) + : AudiocdConfig(parent, name), configChanged(false) +{ + TQString foo = i18n("Report errors found on the cd."); + + setButtons(Default|Apply); + + config = new TDEConfig("kcmaudiocdrc"); + + TQPtrList<AudioCDEncoder> encoders; + AudioCDEncoder::findAllPlugins(0, encoders); + AudioCDEncoder *encoder; + for ( encoder = encoders.first(); encoder; encoder = encoders.next() ){ + if (encoder->init()) { + TDEConfigSkeleton *config = NULL; + TQWidget *widget = encoder->getConfigureWidget(&config); + if(widget && config){ + tabWidget->addTab(widget, i18n("%1 Encoder").arg(encoder->type())); + TDEConfigDialogManager *configManager = new TDEConfigDialogManager(widget, config, TQString(encoder->type()+" EncoderConfigManager").latin1()); + encoderSettings.append(configManager); + } + } + } + + load(); + + TDEConfigDialogManager *widget; + for ( widget = encoderSettings.first(); widget; widget = encoderSettings.next() ){ + connect(widget, TQT_SIGNAL(widgetModified()), this, TQT_SLOT(slotModuleChanged())); + } + + //CDDA Options + connect(cd_specify_device,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotConfigChanged())); + connect(ec_enable_check,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotEcEnable())); + connect(ec_skip_check,TQT_SIGNAL(clicked()),TQT_SLOT(slotConfigChanged())); + connect(cd_device_string,TQT_SIGNAL(textChanged(const TQString &)),TQT_SLOT(slotConfigChanged())); + connect(niceLevel,TQT_SIGNAL(valueChanged(int)),TQT_SLOT(slotConfigChanged())); + + // File Name + connect(fileNameLineEdit, TQT_SIGNAL(textChanged(const TQString &)), this, TQT_SLOT(slotConfigChanged())); + connect(albumNameLineEdit, TQT_SIGNAL(textChanged(const TQString &)), this, TQT_SLOT(slotConfigChanged())); + connect( kcfg_replaceInput, TQT_SIGNAL( textChanged(const TQString&) ), this, TQT_SLOT( updateExample() ) ); + connect( kcfg_replaceOutput, TQT_SIGNAL( textChanged(const TQString&) ), this, TQT_SLOT( updateExample() ) ); + connect( example, TQT_SIGNAL( textChanged(const TQString&) ), this, TQT_SLOT( updateExample() ) ); + connect( kcfg_replaceInput, TQT_SIGNAL( textChanged(const TQString&) ), this, TQT_SLOT( slotConfigChanged() ) ); + connect( kcfg_replaceOutput, TQT_SIGNAL( textChanged(const TQString&) ), this, TQT_SLOT( slotConfigChanged() ) ); + connect( example, TQT_SIGNAL( textChanged(const TQString&) ), this, TQT_SLOT( slotConfigChanged() ) ); + + TDEAboutData *about = + new TDEAboutData(I18N_NOOP("kcmaudiocd"), I18N_NOOP("TDE Audio CD IO Slave"), + 0, 0, TDEAboutData::License_GPL, + I18N_NOOP("(c) 2000 - 2005 Audio CD developers")); + + about->addAuthor("Benjamin C. Meyer", I18N_NOOP("Current Maintainer"), "ben@meyerhome.net"); + about->addAuthor("Carsten Duvenhorst", 0, "duvenhorst@duvnet.de"); + setAboutData(about); +} + +KAudiocdModule::~KAudiocdModule() +{ + delete config; +} + +TQString removeQoutes(const TQString& text) +{ + TQString deqoutedString=text; + TQRegExp qoutedStringRegExp("^\".*\"$"); + if (qoutedStringRegExp.exactMatch(text)) + { + deqoutedString=text.mid(1, text.length()-2); + } + return deqoutedString; +} + +bool needsQoutes(const TQString& text) +{ + TQRegExp spaceAtTheBeginning("^\\s+.*$"); + TQRegExp spaceAtTheEnd("^.*\\s+$"); + return (spaceAtTheBeginning.exactMatch(text) || spaceAtTheEnd.exactMatch(text)); + + +} + +void KAudiocdModule::updateExample() +{ + TQString text = example->text(); + TQString deqoutedReplaceInput=removeQoutes(kcfg_replaceInput->text()); + TQString deqoutedReplaceOutput=removeQoutes(kcfg_replaceOutput->text()); + + text.replace( TQRegExp(deqoutedReplaceInput), deqoutedReplaceOutput ); + exampleOutput->setText(text); +} + +void KAudiocdModule::defaults() { + load( false ); +} + +void KAudiocdModule::save() { + if (!configChanged ) return; + + { + TDEConfigGroupSaver saver(config, "CDDA"); + + // autosearch is the name of the config option, which has the + // reverse sense of the current text of the configuration option, + // which is specify the device. Therefore, invert the value on write. + // + config->writeEntry("autosearch", !(cd_specify_device->isChecked()) ); + config->writeEntry("device",cd_device_string->text()); + config->writeEntry("disable_paranoia",!(ec_enable_check->isChecked())); + config->writeEntry("never_skip",!(ec_skip_check->isChecked())); + config->writeEntry("niceLevel", niceLevel->value()); + } + + { + TDEConfigGroupSaver saver(config, "FileName"); + config->writeEntry("file_name_template", fileNameLineEdit->text()); + config->writeEntry("album_name_template", albumNameLineEdit->text()); + config->writeEntry("regexp_example", example->text()); + // save qouted if required + TQString replaceInput=kcfg_replaceInput->text(); + TQString replaceOutput=kcfg_replaceOutput->text(); + if (needsQoutes(replaceInput)) + { + replaceInput=TQString("\"")+replaceInput+TQString("\""); + } + if (needsQoutes(replaceOutput)) + { + replaceOutput=TQString("\"")+replaceOutput+TQString("\""); + } + config->writeEntry("regexp_search", replaceInput); + config->writeEntry("regexp_replace", replaceOutput); + } + + TDEConfigDialogManager *widget; + for ( widget = encoderSettings.first(); widget; widget = encoderSettings.next() ){ + widget->updateSettings(); + } + + config->sync(); + + configChanged = false; + +} + +void KAudiocdModule::load() { + load( false ); +} + +void KAudiocdModule::load(bool useDefaults) { + + config->setReadDefaults( useDefaults ); + + { + TDEConfigGroupSaver saver(config, "CDDA"); + + + // Specify <=> not autosearch, as explained above in ::save() + cd_specify_device->setChecked( !(config->readBoolEntry("autosearch",true)) ); + cd_device_string->setText(config->readEntry("device","/dev/cdrom")); + ec_enable_check->setChecked(!(config->readBoolEntry("disable_paranoia",false))); + ec_skip_check->setChecked(!(config->readBoolEntry("never_skip",true))); + niceLevel->setValue(config->readNumEntry("niceLevel", 0)); + } + + { + TDEConfigGroupSaver saver(config, "FileName"); + fileNameLineEdit->setText(config->readEntry("file_name_template", "%{albumartist} - %{number} - %{title}")); + albumNameLineEdit->setText(config->readEntry("album_name_template", "%{albumartist} - %{albumtitle}")); + kcfg_replaceInput->setText(config->readEntry("regexp_search")); + kcfg_replaceOutput->setText(config->readEntry("regexp_replace")); + example->setText(config->readEntry("example", i18n("Cool artist - example audio file.wav"))); + } + + TDEConfigDialogManager *widget; + for ( widget = encoderSettings.first(); widget; widget = encoderSettings.next() ){ + widget->updateWidgets(); + } + + emit changed( useDefaults ); +} + +void KAudiocdModule::slotModuleChanged() { + TDEConfigDialogManager *widget; + for ( widget = encoderSettings.first(); widget; widget = encoderSettings.next() ){ + if(widget->hasChanged()){ + slotConfigChanged(); + break; + } + } +} + +void KAudiocdModule::slotConfigChanged() { + configChanged = true; + emit changed(true); +} + +/* +# slot for the error correction settings +*/ +void KAudiocdModule::slotEcEnable() { + if (!(ec_skip_check->isChecked())) { + ec_skip_check->setChecked(true); + } else { + if (ec_skip_check->isEnabled()) { + ec_skip_check->setChecked(false); + } + } + + slotConfigChanged(); +} + +TQString KAudiocdModule::quickHelp() const +{ + return i18n("<h1>Audio CDs</h1> The Audio CD IO-Slave enables you to easily" + " create wav, MP3 or Ogg Vorbis files from your audio CD-ROMs or DVDs." + " The slave is invoked by typing <i>\"audiocd:/\"</i> in Konqueror's location" + " bar. In this module, you can configure" + " encoding, and device settings. Note that MP3 and Ogg" + " Vorbis encoding are only available if TDE was built with a recent" + " version of the LAME or Ogg Vorbis libraries."); +} + +extern "C" +{ + TDECModule *create_audiocd(TQWidget *parent, const char */*name*/) + { + return new KAudiocdModule(parent, "kcmaudiocd"); + } + +} diff --git a/tdeioslave/audiocd/kcmaudiocd/kcmaudiocd.h b/tdeioslave/audiocd/kcmaudiocd/kcmaudiocd.h new file mode 100644 index 00000000..c9ec1bc7 --- /dev/null +++ b/tdeioslave/audiocd/kcmaudiocd/kcmaudiocd.h @@ -0,0 +1,66 @@ +/* + + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Permission is also granted to link this program with the TQt + library, treating TQt like a library that normally accompanies the + operating system kernel, whether or not that is in fact the case. + +*/ + + +#ifndef KAUDIOCDCONFIG_H +#define KAUDIOCDCONFIG_H + +class TDEConfigDialogManager; + +#include "audiocdconfig.h" +class KAudiocdModule : public AudiocdConfig +{ + Q_OBJECT + + +public: + + KAudiocdModule(TQWidget *parent=0, const char *name=0); + ~KAudiocdModule(); + + TQString quickHelp() const; + +public slots: + void defaults(); + void save(); + void load(); + void load(bool useDefaults); + +private slots: + void updateExample(); + void slotConfigChanged(); + void slotEcEnable(); + void slotModuleChanged(); + +private: + TDEConfig *config; + bool configChanged; + + int getBitrateIndex(int value); + + TQPtrList<TDEConfigDialogManager> encoderSettings; +}; + +#endif // KAUDIOCDCONFIG_H + diff --git a/tdeioslave/audiocd/plugins/Makefile.am b/tdeioslave/audiocd/plugins/Makefile.am new file mode 100644 index 00000000..fcee4e68 --- /dev/null +++ b/tdeioslave/audiocd/plugins/Makefile.am @@ -0,0 +1,21 @@ +#if HAVE_VORBIS +#AUDIOCD_PLUGINS_SUBDIR=vorbis +#endif + +SUBDIRS = . wav vorbis lame flac + +INCLUDES = -I$(top_srcdir)/libkcddb $(all_includes) + +lib_LTLIBRARIES = libaudiocdplugins.la + +libaudiocdplugins_la_LIBADD = $(LIB_TDECORE) $(top_builddir)/libkcddb/libkcddb.la + +libaudiocdplugins_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined + +libaudiocdplugins_la_SOURCES = audiocdencoder.cpp + +include_HEADERS = audiocdencoder.h + +messages: + $(XGETTEXT) *.cpp -o $(podir)/tdeio_audiocd.pot + diff --git a/tdeioslave/audiocd/plugins/audiocdencoder.cpp b/tdeioslave/audiocd/plugins/audiocdencoder.cpp new file mode 100644 index 00000000..26c108b8 --- /dev/null +++ b/tdeioslave/audiocd/plugins/audiocdencoder.cpp @@ -0,0 +1,95 @@ +/* + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <audiocdencoder.h> +#include <klibloader.h> +#include <kdebug.h> +#include <tqdir.h> +#include <tqregexp.h> +#include <kstandarddirs.h> + +/** + * Attempt to load a plugin and see if it has the symbol create_audiocd_encoders. + * @param libFileName file to try to load. + * @returns pointer to the symbol or NULL + */ +void *loadPlugin(const TQString &libFileName) +{ +#ifdef DEBUG + kdDebug(7117) << "Trying to load library. File: \"" << libFileName.latin1() << "\"." << endl; +#endif + KLibLoader *loader = KLibLoader::self(); + if (!loader) + return NULL; +#ifdef DEBUG + kdDebug(7117) << "We have a loader. File: \"" << libFileName.latin1() << "\"." << endl; +#endif + KLibrary *lib = loader->library(libFileName.latin1()); + if (!lib) + return NULL; +#ifdef DEBUG + kdDebug(7117) << "We have a library. File: \"" << libFileName.latin1() << "\"." << endl; +#endif + void *cplugin = lib->symbol("create_audiocd_encoders"); + if (!cplugin) + return NULL; +#ifdef DEBUG + kdDebug(7117) << "We have a plugin. File: \"" << libFileName.latin1() << "\"." << endl; +#endif + return cplugin; +} + +/** + * There might be a "better" way of doing this, but I don't know it, + * but I do know that this does work. :) Feel free to improve the loading system, + * there isn't much code anyway. + */ +void AudioCDEncoder::findAllPlugins(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders){ + TQString foundEncoders; + + KStandardDirs standardDirs; + TQStringList dirs = standardDirs.findDirs("module", ""); + for (TQStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it) { + TQDir dir(*it); + if (!dir.exists()) { + kdDebug(7117) << "Directory given by KStandardDirs: " << dir.path() << " doesn't exists!" << endl; + continue; + } + dir.setFilter(TQDir::Files | TQDir::Hidden); + + TQStringList list = dir.entryList( "libaudiocd_encoder_*.so"); + kdDebug() << "list " << list << endl; + for (TQStringList::ConstIterator it2 = list.begin(); it2 != list.end(); ++it2) + { + TQString fileName = *it2; + kdDebug() << fileName << endl; + if (foundEncoders.contains(fileName)) { + kdDebug(7117) << "Warning, encoder has been found twice!" << endl; + continue; + } + foundEncoders.append(fileName); + fileName = fileName.mid(0, fileName.find('.')); + void *function = loadPlugin(fileName); + if(function){ + void (*functionPointer)(TDEIO::SlaveBase *, TQPtrList<AudioCDEncoder> &) = (void (*)(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders)) function; + functionPointer(slave, encoders); + } + } + } +} + diff --git a/tdeioslave/audiocd/plugins/audiocdencoder.h b/tdeioslave/audiocd/plugins/audiocdencoder.h new file mode 100644 index 00000000..56fe7aa5 --- /dev/null +++ b/tdeioslave/audiocd/plugins/audiocdencoder.h @@ -0,0 +1,145 @@ +/* + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef AUDIOCD_ENCODER_H +#define AUDIOCD_ENCODER_H + +#include <sys/types.h> +#include <tdeio/slavebase.h> +#include <cdinfo.h> + +class TDEConfigSkeleton; +using namespace KCDDB; + +class AudioCDEncoder { + +public: + /** + * Constructor. + * @param slave parent that this classes can use to call data() with + * when finished encoding bits. + */ + explicit AudioCDEncoder(TDEIO::SlaveBase *slave) : ioslave(slave) {}; + + /** + * Deconstructor. + */ + virtual ~AudioCDEncoder(){}; + + /** + * Initiallizes the decoder, loading libraries, etc. Encoders + * that don't return true will will deleted and not used. + * @returns false if unable to initialize the encoder. + */ + virtual bool init() = 0; + + /** + * The encoder should read in its config data here. + */ + virtual void loadSettings() = 0; + + /** + * Helper function to determine the end size of a + * encoded file. + * @param time_secs the lengh of the audio track in seconds. + * @returns the size of a file if it is time_secs in length. + */ + virtual unsigned long size(long time_secs) const = 0; + + /** + * @returns the generic user string type/name of this encoder + * Examples: "MP3", "Ogg Vorbis", "Wav", "FID Level 2", etc + */ + virtual TQString type() const = 0; + + /** + * @returns the mime type for the files this encoder produces. + * Example: "audio/x-wav" + */ + virtual const char * mimeType() const = 0; + + /** + * @returns the file type for the files this encoder produces. + * Used in naming of the file for example foo.mp3 + * Examples: "mp3", "ogg", "wav" + */ + virtual const char * fileType() const = 0; + + /** + * Before the read functions are called this is + * called to allow the encoders to store the cddb + * information if they want to so it can be inserted + * where neccessary (start, middle, end, or combos etc). + */ + virtual void fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ) = 0; + + /** + * Perform any initial file creation necessary for a new song (that + * has just been sent via fillSongInfo()) + * @param size - the total binary size of the end file (via size()). + * @return size of the data that was created by this function. + */ + virtual long readInit(long size) = 0; + + /** + * Passes a little bit of cd data to be encoded + * This function is most likly called many many times. + * @param buf pointer to the audio that has been read in so far + * @param frames the number of frames of audio that are in buf + * @return size of the data that was created by this function, -1 on error. + */ + virtual long read(int16_t * buf, int frames) = 0; + + /** + * Perform any final file creation/padding that is necessary + * @return size of the data that was created by this function. + */ + virtual long readCleanup() = 0; + + /** + * Returns a configure widget for the encoder + */ + virtual TQWidget* getConfigureWidget(TDEConfigSkeleton** manager) const + { Q_UNUSED(manager); return NULL; }; + + /** + * Returns the last error message; called when e.g. read() returns -1. + */ + virtual TQString lastErrorMessage() const { return TQString(); } + + /** + * Helper function to load all of the AudioCD Encoders from libraries. + * Uses KStandardDirs to find where libraries could be, opens all of the ones + * that we might own audiocd_encoder_* and then uses the symbol + * create_audiocd_encoders to obtain the encoders from that library. + * @param slave ioslave needed if the plugin is going to be used to encode something. + * @param encoders container for new encoders. + */ + static void findAllPlugins(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders); + +protected: + /** + * Pointer to the ioslave that is running this encoder. + * Used (only?) for the data() function to pass back encoded data. + */ + TDEIO::SlaveBase *ioslave; + +}; + +#endif // AUDIOCD_ENCODER_H + diff --git a/tdeioslave/audiocd/plugins/flac/Makefile.am b/tdeioslave/audiocd/plugins/flac/Makefile.am new file mode 100644 index 00000000..4e693c53 --- /dev/null +++ b/tdeioslave/audiocd/plugins/flac/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/libkcddb -I$(srcdir)/.. $(all_includes) + +kde_module_LTLIBRARIES = libaudiocd_encoder_flac.la + +libaudiocd_encoder_flac_la_SOURCES = encoderflac.cpp + +libaudiocd_encoder_flac_la_LIBADD = $(LIBFLAC) $(LIB_KIO) ../libaudiocdplugins.la + +libaudiocd_encoder_flac_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/audiocd/plugins + +METASOURCES = AUTO diff --git a/tdeioslave/audiocd/plugins/flac/encoderflac.cpp b/tdeioslave/audiocd/plugins/flac/encoderflac.cpp new file mode 100644 index 00000000..ed1c5dde --- /dev/null +++ b/tdeioslave/audiocd/plugins/flac/encoderflac.cpp @@ -0,0 +1,214 @@ +/* + Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com> + Copyright (C) 2005 Benjamin Meyer <ben at meyerhome dot net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "encoderflac.h" + +#ifdef HAVE_LIBFLAC + +#include <FLAC/format.h> +#include <FLAC/metadata.h> +#include <FLAC/stream_encoder.h> + +#include <tdeconfig.h> +#include <kdebug.h> + +#if !defined FLAC_API_VERSION_CURRENT || FLAC_API_VERSION_CURRENT < 8 +#define LEGACY_FLAC +#else +#undef LEGACY_FLAC +#endif + +extern "C" +{ + KDE_EXPORT void create_audiocd_encoders(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders) + { + encoders.append(new EncoderFLAC(slave)); + } +} + +class EncoderFLAC::Private { + +public: + FLAC__StreamEncoder *encoder; + FLAC__StreamMetadata** metadata; + TDEIO::SlaveBase* ioslave; + unsigned long data; +}; + +#ifdef LEGACY_FLAC +static FLAC__StreamEncoderWriteStatus WriteCallback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) +#else +static FLAC__StreamEncoderWriteStatus WriteCallback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data) +#endif +{ + EncoderFLAC::Private *d = (EncoderFLAC::Private*)client_data; + + d->data += bytes; + + TQByteArray output; + + if (bytes) { + output.setRawData((const char*)buffer, bytes); + d->ioslave->data(output); + output.resetRawData((const char*)buffer, bytes); + } + + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + +static void MetadataCallback (const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + // We do not have seekable writeback so we just discard the updated metadata + +} + +/* +static FLAC__SeekableStreamEncoderSeekStatus SeekCallback(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{} ; */ + + + + +EncoderFLAC::EncoderFLAC(TDEIO::SlaveBase *slave) : AudioCDEncoder(slave) { + d = new Private(); + d->ioslave = slave; + d->encoder = 0; +} + +EncoderFLAC::~EncoderFLAC() { + if (d->encoder) FLAC__stream_encoder_delete(d->encoder); + delete d; +} + +bool EncoderFLAC::init(){ + d->encoder = FLAC__stream_encoder_new(); + d->metadata = 0; + d->data = 0; + return true; +} + +void EncoderFLAC::loadSettings() { +// config->setGroup("FLAC"); + +} + +// Estimate size to be 5/8 of uncompresed size. +unsigned long EncoderFLAC::size(long time_secs) const { + long uncompressed = (time_secs * (44100*2*2)); + return (uncompressed/8)*5 + 1000; +} + +long EncoderFLAC::readInit(long size) { + kdDebug(7117) << "EncoderFLAC::readInit() called"<< endl; + d->data = 0; +#ifdef LEGACY_FLAC + FLAC__stream_encoder_set_write_callback(d->encoder, WriteCallback); + FLAC__stream_encoder_set_metadata_callback(d->encoder, MetadataCallback); + FLAC__stream_encoder_set_client_data(d->encoder, d); +#endif + + // The options match approximely those of flac compression-level-3 + FLAC__stream_encoder_set_do_mid_side_stereo(d->encoder, true); + FLAC__stream_encoder_set_loose_mid_side_stereo(d->encoder, true); // flac -M + FLAC__stream_encoder_set_max_lpc_order(d->encoder, 6); // flac -l6 + FLAC__stream_encoder_set_min_residual_partition_order(d->encoder, 3); + FLAC__stream_encoder_set_max_residual_partition_order(d->encoder, 3); // flac -r3,3 + FLAC__stream_encoder_set_blocksize(d->encoder, 4608); + FLAC__stream_encoder_set_streamable_subset(d->encoder, true); + if (size > 0) + FLAC__stream_encoder_set_total_samples_estimate(d->encoder, size/4); + +#ifdef LEGACY_FLAC + if(FLAC__stream_encoder_init(d->encoder) != FLAC__STREAM_ENCODER_OK) + ; // really should handle an init failure +#else + if(FLAC__stream_encoder_init_stream(d->encoder, WriteCallback, NULL, NULL, MetadataCallback, d) != FLAC__STREAM_ENCODER_INIT_STATUS_OK) + ; // really should handle an init failure +#endif + return d->data; +} + +long EncoderFLAC::read(int16_t * buf, int frames) +{ + unsigned long olddata = d->data; + FLAC__int32 *buffer = new FLAC__int32[frames*2]; + for(int i=0; i<frames*2;i++) { + buffer[i] = (FLAC__int32)buf[i]; + } + + bool res = FLAC__stream_encoder_process_interleaved (d->encoder, buffer, frames); + delete[] buffer; + return d->data - olddata; +} + +long EncoderFLAC::readCleanup() +{ + FLAC__stream_encoder_finish(d->encoder); +// FLAC__stream_encoder_delete(d->encoder); + if (d->metadata) { + FLAC__metadata_object_delete(d->metadata[0]); + delete[] d->metadata; + d->metadata = 0; + } + return 0; +} + +void EncoderFLAC::fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ) +{ + d->metadata = new FLAC__StreamMetadata*[1]; + d->metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); +// d->metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); +// d->metadata[2] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE) + + typedef TQPair<TQString, TQVariant> Comment; + Comment comments[7] = { Comment("Title", info.trackInfoList[track].get("title")), + Comment("Artist", info.get("artist")), + Comment("Album", info.get("title")), + Comment("Genre", info.get("genre")), + Comment("Tracknumber", TQString::number(track+1)), + Comment("Comment", comment), + Comment("Date", TQString() )}; + if (info.get("Year").toInt() > 0) { + TQDateTime dt(TQDate(info.get("Year").toInt(), 1, 1)); + comments[6] = Comment("Date", dt.toString(Qt::ISODate)); + } + + FLAC__StreamMetadata_VorbisComment_Entry entry; + TQString field; + TQCString cfield; + int num_comments = 0; + + for(int i=0; i<7; i++) { + if (!comments[i].second.toString().isEmpty()) { + field = comments[i].first+"="+comments[i].second.toString(); + cfield = field.utf8(); + entry.entry = (FLAC__byte*)tqstrdup(cfield); + entry.length = cfield.length(); + // Insert in vorbiscomment and assign ownership of pointers to FLAC + FLAC__metadata_object_vorbiscomment_insert_comment(d->metadata[0], num_comments, entry, false); + num_comments++; + } + } + + FLAC__stream_encoder_set_metadata(d->encoder, d->metadata, 1); +} + +#endif // HAVE_LIBFLAC + diff --git a/tdeioslave/audiocd/plugins/flac/encoderflac.h b/tdeioslave/audiocd/plugins/flac/encoderflac.h new file mode 100644 index 00000000..e563e061 --- /dev/null +++ b/tdeioslave/audiocd/plugins/flac/encoderflac.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2004 Allan Sandfeld Jensen <kde@carewolf.com> + Copyright (C) 2005 Benjamin Meyer <ben at meyerhome dot net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef ENCODER_FLAC_H +#define ENCODER_FLAC_H + +#include <config.h> + +#ifdef HAVE_LIBFLAC + +#include <audiocdencoder.h> + +/** + * FLAC encoder. + * This encoder is only enabled when HAVE_LIBFLAC is set. + * Check out http://flac.sourceforge.net/ for more information. + */ +class EncoderFLAC : public AudioCDEncoder { + +public: + EncoderFLAC(TDEIO::SlaveBase *slave); + ~EncoderFLAC(); + + virtual TQString type() const { return "FLAC"; }; + virtual bool init(); + virtual void loadSettings(); + virtual unsigned long size(long time_secs) const; + virtual const char * fileType() const { return "flac"; }; + virtual const char * mimeType() const { return "audio/x-flac"; } + virtual void fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ); + virtual long readInit(long size); + virtual long read(int16_t * buf, int frames); + virtual long readCleanup(); + + class Private; +private: + Private * d; + +}; + +#endif // HAVE_FLAC + +#endif // ENCODER_FLAC_H + diff --git a/tdeioslave/audiocd/plugins/lame/Makefile.am b/tdeioslave/audiocd/plugins/lame/Makefile.am new file mode 100644 index 00000000..49ddddd9 --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir)/libkcddb -I$(srcdir)/.. $(taglib_includes) $(all_includes) + +kde_kcfg_DATA = audiocd_lame_encoder.kcfg + +kde_module_LTLIBRARIES = libaudiocd_encoder_lame.la + +libaudiocd_encoder_lame_la_SOURCES = audiocd_lame_encoder.kcfgc encoderlame.cpp encoderlameconfig.ui collectingprocess.cpp + +libaudiocd_encoder_lame_la_LIBADD = $(LIB_KIO) ../libaudiocdplugins.la + +libaudiocd_encoder_lame_la_LDFLAGS = -avoid-version -module -no-undefined $(taglib_libs) $(all_libraries) + +pluginsdir = $(kde_datadir)/audiocd/plugins + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/audiocd_encoder_lame.pot diff --git a/tdeioslave/audiocd/plugins/lame/audiocd_lame_encoder.kcfg b/tdeioslave/audiocd/plugins/lame/audiocd_lame_encoder.kcfg new file mode 100644 index 00000000..c752fd81 --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/audiocd_lame_encoder.kcfg @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kcmaudiocd_encoder_lame_rc"/> + <group name="Lame"> + +<!-- Encoding Method --> + <entry name="bitrate_constant" type="Bool"> + <label>Constant Bitrate</label> + <default>false</default> + </entry> + <entry name="bitrate_variable" type="Bool"> + <label>Variable Bitrate</label> + <default>true</default> + </entry> + + <entry name="stereo" type="Int"> + <label>Stereo Mode</label> + <default>0</default> + </entry> + <entry name="quality" type="Int"> + <label>Quality</label> + <default>-2</default> + </entry> + +<!-- Options --> + <entry name="copyright" type="Bool"> + <label>Copyrighted</label> + <default>false</default> + </entry> + <entry name="original" type="Bool"> + <label>Original</label> + <default>true</default> + </entry> + <entry name="iso" type="Bool"> + <label>ISO Encoding</label> + <default>false</default> + </entry> + <entry name="crc" type="Bool"> + <label>Error protection</label> + <default>false</default> + </entry> + <entry name="id3_tag" type="Bool"> + <label>Write ID3 Tag</label> + <default>true</default> + </entry> + +<!-- Constant Bitrate Settings --> + <entry name="cbr_bitrate" type="Int"> + <label>Constant Bitrate Settings</label> + <default>10</default> + <min>0</min> + <max>13</max> + </entry> + +<!-- Variable Bitrate Settings --> + <entry name="vbr_min_br" type="Bool"> + <label>Minimal bitrate</label> + <default>false</default> + </entry> + <entry name="vbr_min_hard" type="Bool"> + <label>Minimal Value is a hard limit</label> + <default>false</default> + </entry> + <entry name="vbr_max_br" type="Bool"> + <label>Maximal bitrate</label> + <default>false</default> + </entry> + <entry name="vbr_average_br" type="Bool"> + <label>Average bitrate</label> + <default>false</default> + </entry> + <entry name="vbr_xing_tag" type="Bool"> + <label>Write Xing VBR tag</label> + <default>true</default> + </entry> + + <entry name="vbr_min_brate" type="Int"> + <label>Minimal bitrate value</label> + <default>40</default> + <min>0</min> + <max>13</max> + </entry> + <entry name="vbr_max_brate" type="Int"> + <label>Maximal bitrate value</label> + <default>13</default> + <min>0</min> + <max>13</max> + </entry> + <entry name="vbr_mean_brate" type="Int"> + <label>Average bitrate value</label> + <default>10</default> + <min>0</min> + <max>13</max> + </entry> + + +<!-- Filter Settings --> + <entry name="enable_lowpass" type="Bool"> + <label>Lowpass filter cutoff above</label> + <default>false</default> + </entry> + <entry name="lowfilterfreq" type="Int"> + <label>Lowpass filter cutoff above Value</label> + <default>18000</default> + </entry> + + <entry name="enable_highpass" type="Bool"> + <label>Highpass filter cutoff above</label> + <default>false</default> + </entry> + <entry name="highfilterfreq" type="Int"> + <label>Highpass filter cutoff above Value</label> + <default>0</default> + </entry> + + <entry name="set_lpf_width" type="Bool"> + <label>Lowpass filter width</label> + <default>false</default> + </entry> + <entry name="lowfilterwidth" type="Int"> + <label>Lowpass filter width value</label> + <default>900</default> + </entry> + + <entry name="set_hpf_width" type="Bool"> + <label>Highpass filter width</label> + <default>false</default> + </entry> + <entry name="highfilterwidth" type="Int"> + <label>Highpass filter width</label> + <default>0</default> + </entry> + </group> +</kcfg> + diff --git a/tdeioslave/audiocd/plugins/lame/audiocd_lame_encoder.kcfgc b/tdeioslave/audiocd/plugins/lame/audiocd_lame_encoder.kcfgc new file mode 100644 index 00000000..b62f454d --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/audiocd_lame_encoder.kcfgc @@ -0,0 +1,4 @@ +# Code generation options for tdeconfig_compiler +File=audiocd_lame_encoder.kcfg +ClassName=Settings +Singleton=true diff --git a/tdeioslave/audiocd/plugins/lame/collectingprocess.cpp b/tdeioslave/audiocd/plugins/lame/collectingprocess.cpp new file mode 100644 index 00000000..4eaf5304 --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/collectingprocess.cpp @@ -0,0 +1,134 @@ +/* + collectingprocess.cpp + + This file is part of libtdepim. + Copyright (c) 2004 Ingo Kloecker <kloecker@kde.org> + + This library 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 library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the TQt library by Trolltech AS, Norway (or with modified versions + of TQt that use the same license as TQt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + TQt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#include "collectingprocess.h" + +#include <tqvaluelist.h> + +#include <string.h> + +struct CollectingProcess::Private { + Private() : stdoutSize( 0 ), stderrSize( 0 ) + {} + + uint stdoutSize; + TQValueList<TQByteArray> stdoutBuffer; + uint stderrSize; + TQValueList<TQByteArray> stderrBuffer; +}; + + +CollectingProcess::CollectingProcess( TQObject * parent, const char * name ) + : TDEProcess( parent, name ) +{ + d = new Private(); +} + +CollectingProcess::~CollectingProcess() { + delete d; d = 0; +} + +bool CollectingProcess::start( RunMode runmode, Communication comm ) { + // prevent duplicate connection + disconnect( this, TQT_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ), + this, TQT_SLOT( slotReceivedStdout( TDEProcess *, char *, int ) ) ); + if ( comm & Stdout ) { + connect( this, TQT_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ), + this, TQT_SLOT( slotReceivedStdout( TDEProcess *, char *, int ) ) ); + } + // prevent duplicate connection + disconnect( this, TQT_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ), + this, TQT_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) ); + if ( comm & Stderr ) { + connect( this, TQT_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ), + this, TQT_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) ); + } + return TDEProcess::start( runmode, comm ); +} + +void CollectingProcess::slotReceivedStdout( TDEProcess *, char *buf, int len ) +{ + TQByteArray b; + b.duplicate( buf, len ); + d->stdoutBuffer.append( b ); + d->stdoutSize += len; +} + +void CollectingProcess::slotReceivedStderr( TDEProcess *, char *buf, int len ) +{ + TQByteArray b; + b.duplicate( buf, len ); + d->stderrBuffer.append( b ); + d->stderrSize += len; +} + +TQByteArray CollectingProcess::collectedStdout() +{ + if ( d->stdoutSize == 0 ) { + return TQByteArray(); + } + + uint offset = 0; + TQByteArray b( d->stdoutSize ); + for ( TQValueList<TQByteArray>::const_iterator it = d->stdoutBuffer.begin(); + it != d->stdoutBuffer.end(); + ++it ) { + memcpy( b.data() + offset, (*it).data(), (*it).size() ); + offset += (*it).size(); + } + d->stdoutBuffer.clear(); + d->stdoutSize = 0; + + return b; +} + +TQByteArray CollectingProcess::collectedStderr() +{ + if ( d->stderrSize == 0 ) { + return TQByteArray(); + } + + uint offset = 0; + TQByteArray b( d->stderrSize ); + for ( TQValueList<TQByteArray>::const_iterator it = d->stderrBuffer.begin(); + it != d->stderrBuffer.end(); + ++it ) { + memcpy( b.data() + offset, (*it).data(), (*it).size() ); + offset += (*it).size(); + } + d->stderrBuffer.clear(); + d->stderrSize = 0; + + return b; +} + +#include "collectingprocess.moc" diff --git a/tdeioslave/audiocd/plugins/lame/collectingprocess.h b/tdeioslave/audiocd/plugins/lame/collectingprocess.h new file mode 100644 index 00000000..df5c180d --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/collectingprocess.h @@ -0,0 +1,73 @@ +/* -*- mode: C++ -*- + collectingprocess.h + + This file is a copy of the collectingprocess.h which is part of tdepim/libtdepim. + Copyright (c) 2004 Ingo Kloecker <kloecker@kde.org> + + This library 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 library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the TQt library by Trolltech AS, Norway (or with modified versions + of TQt that use the same license as TQt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + TQt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __COLLECTINGPROCESS_H__ +#define __COLLECTINGPROCESS_H__ + +#include <kprocess.h> + +/** + * @short An output collecting TDEProcess class. + * + * This class simplifies the usage of TDEProcess by collecting all output + * (stdout/stderr) of the process. + * + * @author Ingo Kloecker <kloecker@kde.org> + */ +class CollectingProcess : public TDEProcess { + Q_OBJECT + +public: + CollectingProcess( TQObject * parent = 0, const char * name = 0 ); + ~CollectingProcess(); + + /** Starts the process in NotifyOnExit mode and writes in to stdin of + the process. + */ + bool start( RunMode runmode, Communication comm ); + + /** Returns the contents of the stdout buffer and clears it afterwards. */ + TQByteArray collectedStdout(); + /** Returns the contents of the stderr buffer and clears it afterwards. */ + TQByteArray collectedStderr(); + +private slots: + void slotReceivedStdout( TDEProcess *, char *, int ); + void slotReceivedStderr( TDEProcess *, char *, int ); + +private: + class Private; + Private * d; +protected: +}; + +#endif // __COLLECTINGPROCESS_H__ diff --git a/tdeioslave/audiocd/plugins/lame/encoderlame.cpp b/tdeioslave/audiocd/plugins/lame/encoderlame.cpp new file mode 100644 index 00000000..8984bb33 --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/encoderlame.cpp @@ -0,0 +1,366 @@ +/* + Copyright (C) 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <config.h> +#include <endian.h> +#include "encoderlame.h" +#include "encoderlameconfig.h" +#include "audiocd_lame_encoder.h" + +#include <kdebug.h> +#include <tqgroupbox.h> +#include <kprocess.h> +#include <kdebug.h> + +#include <kglobal.h> +#include <klocale.h> +#include <kapplication.h> +#include <tqfileinfo.h> +#include <ktempfile.h> +#include <kstandarddirs.h> +#include "collectingprocess.h" + +extern "C" +{ + KDE_EXPORT void create_audiocd_encoders(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders) { + encoders.append(new EncoderLame(slave)); + } +} + +static int bitrates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }; + +class EncoderLame::Private +{ +public: + int bitrate; + bool waitingForWrite; + bool processHasExited; + TQString lastErrorMessage; + TQStringList genreList; + uint lastSize; + TDEProcess *currentEncodeProcess; + KTempFile *tempFile; +}; + +EncoderLame::EncoderLame(TDEIO::SlaveBase *slave) : TQObject(), AudioCDEncoder(slave) { + d = new Private(); + d->waitingForWrite = false; + d->processHasExited = false; + d->lastSize = 0; + loadSettings(); +} + +EncoderLame::~EncoderLame(){ + delete d; +} + +TQWidget* EncoderLame::getConfigureWidget(TDEConfigSkeleton** manager) const { + (*manager) = Settings::self(); + TDEGlobal::locale()->insertCatalogue("audiocd_encoder_lame"); + EncoderLameConfig *config = new EncoderLameConfig(); + config->cbr_settings->hide(); + return config; +} + +bool EncoderLame::init(){ + // Determine if lame is installed on the system or not. + if ( KStandardDirs::findExe( "lame" ).isEmpty() ) + return false; + + // Ask lame for the list of genres it knows; otherwise it barfs when doing + // e.g. lame --tg 'Vocal Jazz' + CollectingProcess proc; + proc << "lame" << "--genre-list"; + proc.start(TDEProcess::Block, TDEProcess::Stdout); + + if(proc.exitStatus() != 0) + return false; + + const TQByteArray data = proc.collectedStdout(); + TQString str; + if ( !data.isEmpty() ) + str = TQString::fromLocal8Bit( data, data.size() ); + + d->genreList = TQStringList::split( '\n', str ); + // Remove the numbers in front of every genre + for( TQStringList::Iterator it = d->genreList.begin(); it != d->genreList.end(); ++it ) { + TQString& genre = *it; + uint i = 0; + while ( i < genre.length() && ( genre[i].isSpace() || genre[i].isDigit() ) ) + ++i; + genre = genre.mid( i ); + + } + //kdDebug(7117) << "Available genres:" << d->genreList << endl; + + return true; +} + +void EncoderLame::loadSettings(){ + // Generate the command line arguments for the current settings + args.clear(); + + Settings *settings = Settings::self(); + + int quality = settings->quality(); + if (quality < 0 ) quality = quality *-1; + if (quality > 9) quality = 9; + + int method = settings->bitrate_constant() ? 0 : 1 ; + + if (method == 0) { + // Constant Bitrate Encoding + args.append("-b"); + args.append(TQString("%1").arg(bitrates[settings->cbr_bitrate()])); + d->bitrate = bitrates[settings->cbr_bitrate()]; + args.append("-q"); + args.append(TQString("%1").arg(quality)); + } + else { + // Variable Bitrate Encoding + if (settings->vbr_average_br()) { + args.append("--abr"); + args.append(TQString("%1").arg(bitrates[settings->vbr_mean_brate()])); + d->bitrate = bitrates[settings->vbr_mean_brate()]; + if (settings->vbr_min_br()){ + args.append("-b"); + args.append(TQString("%1").arg(bitrates[settings->vbr_min_brate()])); + } + if (settings->vbr_min_hard()) + args.append("-F"); + if (settings->vbr_max_br()){ + args.append("-B"); + args.append(TQString("%1").arg(bitrates[settings->vbr_max_brate()])); + } + } else { + d->bitrate = 128; + args.append("-V"); + args.append(TQString("%1").arg(quality)); + } + if ( !settings->vbr_xing_tag() ) + args.append("-t"); + } + + args.append("-m"); + switch ( settings->stereo() ) { + case 0: + args.append("s"); + break; + case 1: + args.append("j"); + break; + case 2: + args.append("d"); + break; + case 3: + args.append("m"); + break; + default: + args.append("s"); + break; + } + + if(settings->copyright()) + args.append("-c"); + if(!settings->original()) + args.append("-o"); + if(settings->iso()) + args.append("--strictly-enforce-ISO"); + if(settings->crc()) + args.append("-p"); + + if ( settings->enable_lowpass() ) { + args.append("--lowpass"); + args.append(TQString("%1").arg(settings->lowfilterfreq())); + + if (settings->set_lpf_width()){ + args.append("--lowpass-width"); + args.append(TQString("%1").arg(settings->lowfilterwidth())); + } + } + + if ( settings->enable_highpass()) { + args.append("--hipass"); + args.append(TQString("%1").arg(settings->highfilterfreq())); + + if (settings->set_hpf_width()){ + args.append("--hipass-width"); + args.append(TQString("%1").arg(settings->highfilterwidth())); + } + } +} + +unsigned long EncoderLame::size(long time_secs) const { + return (time_secs * d->bitrate * 1000)/8; +} + +long EncoderLame::readInit(long /*size*/){ + // Create TDEProcess + d->currentEncodeProcess = new TDEProcess(0); + TQString prefix = locateLocal("tmp", ""); + d->tempFile = new KTempFile(prefix, ".mp3"); + d->tempFile->setAutoDelete(true); + d->lastErrorMessage = TQString(); + d->processHasExited = false; + + // -x bitswap + // -r raw/pcm + // -s 44.1 (because it is raw you have to specify this) +// #if __BYTE_ORDER == __LITTLE_ENDIAN +// *(d->currentEncodeProcess) << "lame" << "--verbose" << "-x" << "-r" << "-s" << "44.1"; +// #else + *(d->currentEncodeProcess) << "lame" << "--verbose" << "-r" << "-s" << "44.1"; +// #endif + + *(d->currentEncodeProcess) << args; + if(Settings::self()->id3_tag()) + *d->currentEncodeProcess << trackInfo; + + // Read in stdin, output to the temp file + *d->currentEncodeProcess << "-" << d->tempFile->name().latin1(); + + //kdDebug(7117) << d->currentEncodeProcess->args() << endl; + + + connect(d->currentEncodeProcess, TQT_SIGNAL(receivedStdout(TDEProcess *, char *, int)), + this, TQT_SLOT(receivedStdout(TDEProcess *, char *, int))); + connect(d->currentEncodeProcess, TQT_SIGNAL(receivedStderr(TDEProcess *, char *, int)), + this, TQT_SLOT(receivedStderr(TDEProcess *, char *, int))); + connect(d->currentEncodeProcess, TQT_SIGNAL(wroteStdin(TDEProcess *)), + this, TQT_SLOT(wroteStdin(TDEProcess *))); + + connect(d->currentEncodeProcess, TQT_SIGNAL(processExited(TDEProcess *)), + this, TQT_SLOT(processExited(TDEProcess *))); + + // Launch! + d->currentEncodeProcess->start(TDEProcess::NotifyOnExit, KShellProcess::All); + return 0; +} + +void EncoderLame::processExited ( TDEProcess *process ){ + kdDebug(7117) << "Lame Encoding process exited with: " << process->exitStatus() << endl; + d->processHasExited = true; +} + +void EncoderLame::receivedStderr( TDEProcess * /*process*/, char *buffer, int /*buflen*/ ){ + kdDebug(7117) << "Lame stderr: " << buffer << endl; + if ( !d->lastErrorMessage.isEmpty() ) + d->lastErrorMessage += '\t'; + d->lastErrorMessage += TQString::fromLocal8Bit( buffer ); +} + +void EncoderLame::receivedStdout( TDEProcess * /*process*/, char *buffer, int /*length*/ ){ + kdDebug(7117) << "Lame stdout: " << buffer << endl; +} + +void EncoderLame::wroteStdin( TDEProcess * /*procces*/ ){ + d->waitingForWrite = false; +} + +long EncoderLame::read(int16_t *buf, int frames){ + if(!d->currentEncodeProcess) + return 0; + if (d->processHasExited) + return -1; + + // Pipe the raw data to lame + char * cbuf = reinterpret_cast<char *>(buf); + d->currentEncodeProcess->writeStdin( cbuf, frames*4); + + // We can't return until the buffer has been written + d->waitingForWrite = true; + while(d->waitingForWrite && d->currentEncodeProcess->isRunning()){ + kapp->processEvents(); + usleep(1); + } + + // Determine the file size increase + TQFileInfo file(d->tempFile->name()); + uint change = file.size() - d->lastSize; + d->lastSize = file.size(); + return change; +} + +long EncoderLame::readCleanup(){ + if(!d->currentEncodeProcess) + return 0; + + // Let lame tag the first frame of the mp3 + d->currentEncodeProcess->closeStdin(); + while( d->currentEncodeProcess->isRunning()){ + kapp->processEvents(); + usleep(1); + } + + // Now copy the file out of the temp into kio + TQFile file( d->tempFile->name() ); + if ( file.open( IO_ReadOnly ) ) { + TQByteArray output; + char data[1024]; + while ( !file.atEnd() ) { + uint read = file.readBlock(data, 1024); + output.setRawData(data, read); + ioslave->data(output); + output.resetRawData(data, read); + } + file.close(); + } + + // cleanup the process and temp + delete d->currentEncodeProcess; + delete d->tempFile; + d->lastSize = 0; + + return 0; +} + +void EncoderLame::fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ){ + trackInfo.clear(); + trackInfo.append("--tt"); + trackInfo.append(info.trackInfoList[track].get("title").toString()); + + trackInfo.append("--ta"); + trackInfo.append(info.get("artist").toString()); + + trackInfo.append("--tl"); + trackInfo.append(info.get("title").toString()); + + trackInfo.append("--ty"); + trackInfo.append(TQString("%1").arg(info.get("year").toString())); + + trackInfo.append("--tc"); + trackInfo.append(comment); + + trackInfo.append("--tn"); + trackInfo.append(TQString("%1").arg(track+1)); + + const TQString genre = info.get( "genre" ).toString(); + if ( d->genreList.find( genre ) != d->genreList.end() ) + { + trackInfo.append("--tg"); + trackInfo.append(genre); + } +} + + +TQString EncoderLame::lastErrorMessage() const +{ + return d->lastErrorMessage; +} + +#include "encoderlame.moc" diff --git a/tdeioslave/audiocd/plugins/lame/encoderlame.h b/tdeioslave/audiocd/plugins/lame/encoderlame.h new file mode 100644 index 00000000..09c323c3 --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/encoderlame.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef ENCODER_LAME_H +#define ENCODER_LAME_H + +#include "audiocdencoder.h" + +class TDEProcess; + +/** + * MP3 encoder using the LAME encoder. + * Go to http://lame.sourceforge.net/ for lots of information. + */ +class EncoderLame : public TQObject, public AudioCDEncoder { + +Q_OBJECT + + +public: + EncoderLame(TDEIO::SlaveBase *slave); + ~EncoderLame(); + + virtual TQString type() const { return "MP3"; }; + virtual bool init(); + virtual void loadSettings(); + virtual unsigned long size(long time_secs) const; + virtual const char * fileType() const { return "mp3"; }; + virtual const char * mimeType() const { return "audio/x-mp3"; }; + virtual void fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ); + virtual long readInit(long size); + virtual long read(int16_t * buf, int frames); + virtual long readCleanup(); + virtual TQString lastErrorMessage() const; + + virtual TQWidget* getConfigureWidget(TDEConfigSkeleton** manager) const; + +protected slots: + void wroteStdin(TDEProcess *proc); + void receivedStdout(TDEProcess *, char *buffer, int length); + void receivedStderr(TDEProcess *proc, char *buffer, int buflen); + void processExited(TDEProcess *proc); + +private: + class Private; + Private * d; + + TQStringList args; + TQStringList trackInfo; +}; + +#endif // ENCODER_LAME_H + diff --git a/tdeioslave/audiocd/plugins/lame/encoderlameconfig.ui b/tdeioslave/audiocd/plugins/lame/encoderlameconfig.ui new file mode 100644 index 00000000..f8149741 --- /dev/null +++ b/tdeioslave/audiocd/plugins/lame/encoderlameconfig.ui @@ -0,0 +1,930 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>EncoderLameConfig</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>LameConfig</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>471</width> + <height>598</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox" row="0" column="1"> + <property name="name"> + <cstring>GroupBox1_2</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>kcfg_copyright</cstring> + </property> + <property name="text"> + <string>Cop&yrighted</string> + </property> + <property name="toolTip" stdset="0"> + <string>Mark MP3 file as copyrighted</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Mark MP3 file as copyrighted.</string> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>kcfg_original</cstring> + </property> + <property name="text"> + <string>Origi&nal</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Mark MP3 file as an original</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Mark MP3 file as an original.</string> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>kcfg_iso</cstring> + </property> + <property name="text"> + <string>&ISO encoding</string> + </property> + <property name="toolTip" stdset="0"> + <string>Try to use strict ISO encoding</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This selects the maximal bitrate used for encoding.</string> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>kcfg_crc</cstring> + </property> + <property name="text"> + <string>&Error protection</string> + </property> + </widget> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>kcfg_id3_tag</cstring> + </property> + <property name="text"> + <string>&Write ID3 tag</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>If checked and if cddb support is available, an id3 tag will be appended</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If checked and if cddb support is available, an id3 tag will be appended</string> + </property> + </widget> + </vbox> + </widget> + <widget class="TQButtonGroup" row="0" column="0"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>Encoding Method</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLayoutWidget" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>Layout21</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>TextLabel3_2</cstring> + </property> + <property name="text"> + <string>Low</string> + </property> + </widget> + <widget class="TQSlider"> + <property name="name"> + <cstring>kcfg_quality</cstring> + </property> + <property name="minValue"> + <number>-9</number> + </property> + <property name="maxValue"> + <number>0</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>-7</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>NoMarks</enum> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>TextLabel2_2</cstring> + </property> + <property name="text"> + <string>High</string> + </property> + </widget> + </hbox> + </widget> + <widget class="TQLabel" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>TextLabel1_2</cstring> + </property> + <property name="text"> + <string>&Quality:</string> + </property> + <property name="alignment"> + <set>AlignLeft</set> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_quality</cstring> + </property> + </widget> + <widget class="TQComboBox" row="1" column="0" rowspan="1" colspan="2"> + <item> + <property name="text"> + <string>Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Joint Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Dual Channel</string> + </property> + </item> + <item> + <property name="text"> + <string>Mono</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_stereo</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>This option controls whether MP3 files are recorded with one or two channels. Note that choosing <i>"Mono"</i> reduces file size, but also kills the stereo signal.</string> + </property> + </widget> + <widget class="TQRadioButton" row="0" column="0"> + <property name="name"> + <cstring>kcfg_bitrate_constant</cstring> + </property> + <property name="text"> + <string>Constant bitrate</string> + </property> + </widget> + <widget class="TQRadioButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_bitrate_variable</cstring> + </property> + <property name="text"> + <string>Variable bitrate</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <spacer row="4" column="0"> + <property name="name"> + <cstring>spacer11</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="TQGroupBox" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>vbr_settings</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="title"> + <string>Variable Bitrate Settings</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQCheckBox" row="3" column="0"> + <property name="name"> + <cstring>kcfg_vbr_average_br</cstring> + </property> + <property name="text"> + <string>Specify avera&ge bitrate:</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This selects the maximal bitrate used for encoding.</string> + </property> + </widget> + <widget class="TQComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>32 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>40 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>48 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>56 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>64 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>80 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>96 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>112 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>224 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>320 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_vbr_max_brate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="currentItem"> + <number>13</number> + </property> + </widget> + <widget class="TQCheckBox" row="2" column="0"> + <property name="name"> + <cstring>kcfg_vbr_max_br</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Maximal bi&trate:</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This selects the maximal bitrate used for encoding.</string> + </property> + </widget> + <widget class="TQCheckBox" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kcfg_vbr_xing_tag</cstring> + </property> + <property name="text"> + <string>Write &Xing VBR tag</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>This writes additional information related to VBR as introduced by Xing.</string> + </property> + </widget> + <widget class="TQComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>32 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>40 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>48 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>56 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>64 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>80 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>96 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>112 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>224 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>320 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_vbr_mean_brate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="currentItem"> + <number>9</number> + </property> + </widget> + <widget class="TQCheckBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kcfg_vbr_min_hard</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Minimal &value is a hard limit</string> + </property> + </widget> + <widget class="TQCheckBox" row="0" column="0"> + <property name="name"> + <cstring>kcfg_vbr_min_br</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Minimal &bitrate:</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This selects the minimal bitrate used for encoding.</string> + </property> + </widget> + <widget class="TQComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>32 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>40 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>48 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>56 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>64 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>80 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>96 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>112 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>224 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>320 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_vbr_min_brate</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="currentItem"> + <number>1</number> + </property> + </widget> + </grid> + </widget> + <widget class="TQGroupBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>cbr_settings</cstring> + </property> + <property name="title"> + <string>Constant Bitrate Settings</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>TextLabel4_2</cstring> + </property> + <property name="text"> + <string>Bitrate:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>kcfg_cbr_bitrate</cstring> + </property> + </widget> + <widget class="TQComboBox"> + <item> + <property name="text"> + <string>32 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>40 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>48 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>56 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>64 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>80 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>96 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>112 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>224 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>320 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_cbr_bitrate</cstring> + </property> + <property name="currentItem"> + <number>9</number> + </property> + <property name="whatsThis" stdset="0"> + <string>The higher the bitrate, the better the quality and the larger the file.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="TQGroupBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>GroupBox83_2</cstring> + </property> + <property name="title"> + <string>Filter Settings</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignLeft</set> + </property> + <property name="hAlign" stdset="0"> + </property> + <property name="vAlign" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQCheckBox" row="0" column="0"> + <property name="name"> + <cstring>kcfg_enable_lowpass</cstring> + </property> + <property name="text"> + <string>&Lowpass filter cutoff above</string> + </property> + </widget> + <widget class="TQSpinBox" row="1" column="0"> + <property name="name"> + <cstring>kcfg_lowfilterfreq</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> Hz</string> + </property> + <property name="maxValue"> + <number>20000</number> + </property> + </widget> + <widget class="TQCheckBox" row="2" column="0"> + <property name="name"> + <cstring>kcfg_enable_highpass</cstring> + </property> + <property name="text"> + <string>&Highpass filter cutoff below</string> + </property> + </widget> + <widget class="TQSpinBox" row="3" column="0"> + <property name="name"> + <cstring>kcfg_highfilterfreq</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> Hz</string> + </property> + <property name="maxValue"> + <number>200</number> + </property> + </widget> + <widget class="TQCheckBox" row="0" column="1"> + <property name="name"> + <cstring>kcfg_set_lpf_width</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Low&pass filter width</string> + </property> + </widget> + <widget class="TQSpinBox" row="1" column="1"> + <property name="name"> + <cstring>kcfg_lowfilterwidth</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> Hz</string> + </property> + <property name="maxValue"> + <number>5000</number> + </property> + </widget> + <widget class="TQCheckBox" row="2" column="1"> + <property name="name"> + <cstring>kcfg_set_hpf_width</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Highpa&ss filter width</string> + </property> + </widget> + <widget class="TQSpinBox" row="3" column="1"> + <property name="name"> + <cstring>kcfg_highfilterwidth</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> Hz</string> + </property> + <property name="maxValue"> + <number>50</number> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>kcfg_bitrate_constant</sender> + <signal>toggled(bool)</signal> + <receiver>cbr_settings</receiver> + <slot>setShown(bool)</slot> + </connection> + <connection> + <sender>kcfg_enable_highpass</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_highfilterfreq</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_enable_highpass</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_highfilterwidth</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_enable_lowpass</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_lowfilterfreq</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_enable_lowpass</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_lowfilterwidth</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_enable_highpass</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_set_hpf_width</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_enable_lowpass</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_set_lpf_width</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_vbr_average_br</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_vbr_max_br</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_vbr_max_br</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_vbr_max_brate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_vbr_average_br</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_vbr_mean_brate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_vbr_average_br</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_vbr_min_br</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_vbr_min_br</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_vbr_min_brate</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_vbr_min_br</sender> + <signal>toggled(bool)</signal> + <receiver>kcfg_vbr_min_hard</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>kcfg_bitrate_variable</sender> + <signal>toggled(bool)</signal> + <receiver>vbr_settings</receiver> + <slot>setShown(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>kcfg_bitrate_variable</tabstop> + <tabstop>kcfg_stereo</tabstop> + <tabstop>kcfg_quality</tabstop> + <tabstop>kcfg_copyright</tabstop> + <tabstop>kcfg_original</tabstop> + <tabstop>kcfg_iso</tabstop> + <tabstop>kcfg_crc</tabstop> + <tabstop>kcfg_id3_tag</tabstop> + <tabstop>kcfg_cbr_bitrate</tabstop> + <tabstop>kcfg_vbr_min_br</tabstop> + <tabstop>kcfg_vbr_min_hard</tabstop> + <tabstop>kcfg_vbr_max_br</tabstop> + <tabstop>kcfg_vbr_average_br</tabstop> + <tabstop>kcfg_vbr_xing_tag</tabstop> + <tabstop>kcfg_vbr_min_brate</tabstop> + <tabstop>kcfg_vbr_max_brate</tabstop> + <tabstop>kcfg_vbr_mean_brate</tabstop> + <tabstop>kcfg_enable_lowpass</tabstop> + <tabstop>kcfg_lowfilterfreq</tabstop> + <tabstop>kcfg_enable_highpass</tabstop> + <tabstop>kcfg_highfilterfreq</tabstop> + <tabstop>kcfg_set_lpf_width</tabstop> + <tabstop>kcfg_lowfilterwidth</tabstop> + <tabstop>kcfg_set_hpf_width</tabstop> + <tabstop>kcfg_highfilterwidth</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/tdeioslave/audiocd/plugins/vorbis/Makefile.am b/tdeioslave/audiocd/plugins/vorbis/Makefile.am new file mode 100644 index 00000000..e83240ff --- /dev/null +++ b/tdeioslave/audiocd/plugins/vorbis/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir)/libkcddb -I$(srcdir)/.. $(all_includes) + +kde_kcfg_DATA = audiocd_vorbis_encoder.kcfg + +kde_module_LTLIBRARIES = libaudiocd_encoder_vorbis.la + +libaudiocd_encoder_vorbis_la_SOURCES = audiocd_vorbis_encoder.kcfgc encodervorbis.cpp encodervorbisconfig.ui + +libaudiocd_encoder_vorbis_la_LIBADD = $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(VORBISENC_LIBS) $(LIB_KIO) ../libaudiocdplugins.la + +libaudiocd_encoder_vorbis_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/audiocd/plugins + +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/audiocd_encoder_vorbis.pot diff --git a/tdeioslave/audiocd/plugins/vorbis/audiocd_vorbis_encoder.kcfg b/tdeioslave/audiocd/plugins/vorbis/audiocd_vorbis_encoder.kcfg new file mode 100644 index 00000000..53465f6c --- /dev/null +++ b/tdeioslave/audiocd/plugins/vorbis/audiocd_vorbis_encoder.kcfg @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kcmaudiocd_encoder_vorbis_rc"/> + <group name="Vorbis"> + + <entry name="vorbis_enc_method" type="Int"> + <label>Vorbis Encoding Quality or Bitrate</label> + <default>0</default> + </entry> + + <entry name="set_vorbis_min_br" type="Bool"> + <label>Minimal bitrate specified</label> + <default>false</default> + </entry> + <entry name="set_vorbis_max_br" type="Bool"> + <label>Maximal bitrate specified</label> + <default>false</default> + </entry> + <entry name="set_vorbis_nominal_br" type="Bool"> + <label>Average bitrate specified</label> + <default>true</default> + </entry> + + <entry name="vorbis_comments" type="Bool"> + <label>Add Comments</label> + <default>true</default> + </entry> + <entry name="vorbis_quality" type="Double"> + <label>Quality</label> + <default>3</default> + <min>-1</min> + <max>10</max> + </entry> + + <entry name="vorbis_min_br" type="Int"> + <label>Minimal bitrate</label> + <default>1</default> + <min>0</min> + <max>13</max> + </entry> + + <entry name="vorbis_max_br" type="Int"> + <label>maximal bitrate</label> + <default>13</default> + <min>0</min> + <max>13</max> + </entry> + + <entry name="vorbis_nominal_br" type="Int"> + <label>maximal bitrate</label> + <default>3</default> + <min>0</min> + <max>5</max> + </entry> + +<!-- + <entry name="vorbis_nominal_br" type="Enum"> + <label>maximal bitrate</label> + <default>150</default> + <choices> + <choice name="32"/> + <choice name="40"/> + <choice name="48"/> + <choice name="56"/> + <choice name="64"/> + <choice name="80"/> + <choice name="96"/> + <choice name="112"/> + <choice name="128"/> + <choice name="160"/> + <choice name="192"/> + <choice name="224"/> + <choice name="256"/> + <choice name="350"/> + </choices> + </entry> --> + + + </group> +</kcfg> + diff --git a/tdeioslave/audiocd/plugins/vorbis/audiocd_vorbis_encoder.kcfgc b/tdeioslave/audiocd/plugins/vorbis/audiocd_vorbis_encoder.kcfgc new file mode 100644 index 00000000..da857139 --- /dev/null +++ b/tdeioslave/audiocd/plugins/vorbis/audiocd_vorbis_encoder.kcfgc @@ -0,0 +1,4 @@ +# Code generation options for tdeconfig_compiler +File=audiocd_vorbis_encoder.kcfg +ClassName=Settings +Singleton=true diff --git a/tdeioslave/audiocd/plugins/vorbis/encodervorbis.cpp b/tdeioslave/audiocd/plugins/vorbis/encodervorbis.cpp new file mode 100644 index 00000000..048a46e0 --- /dev/null +++ b/tdeioslave/audiocd/plugins/vorbis/encodervorbis.cpp @@ -0,0 +1,336 @@ +/* + Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "encodervorbis.h" +#include "audiocd_vorbis_encoder.h" +#include "encodervorbisconfig.h" + +#ifdef HAVE_VORBIS + +#include <vorbis/vorbisenc.h> +#include <time.h> +#include <stdlib.h> +#include <tdeconfig.h> +#include <knuminput.h> +#include <tqgroupbox.h> + +#include <kglobal.h> +#include <klocale.h> + +extern "C" +{ + KDE_EXPORT void create_audiocd_encoders(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders) + { + encoders.append(new EncoderVorbis(slave)); + } +} + +// these are the approx. bitrates for the current 5 Vorbis modes +static int vorbis_nominal_bitrates[] = { 128, 160, 192, 256, 350 }; +static int vorbis_bitrates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 350 }; + +class EncoderVorbis::Private { + +public: + ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + + vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ + vorbis_comment vc; /* struct that stores all the user comments */ + + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + bool write_vorbis_comments; + long vorbis_bitrate_lower; + long vorbis_bitrate_upper; + long vorbis_bitrate_nominal; + int vorbis_encode_method; + double vorbis_quality; + int vorbis_bitrate; +}; + +EncoderVorbis::EncoderVorbis(TDEIO::SlaveBase *slave) : AudioCDEncoder(slave) { + d = new Private(); +} + +EncoderVorbis::~EncoderVorbis(){ + delete d; +} + +TQWidget* EncoderVorbis::getConfigureWidget(TDEConfigSkeleton** manager) const { + (*manager) = Settings::self(); + TDEGlobal::locale()->insertCatalogue("audiocd_encoder_vorbis"); + EncoderVorbisConfig *config = new EncoderVorbisConfig(); + config->kcfg_vorbis_quality->setRange(0.0, 10.0, 0.2, true); + config->vorbis_bitrate_settings->hide(); + return config; +} + +bool EncoderVorbis::init(){ + vorbis_info_init(&d->vi); + vorbis_comment_init(&d->vc); + + vorbis_comment_add_tag + ( + &d->vc, + const_cast<char *>("kde-encoder"), + const_cast<char *>("kio_audiocd") + ); + return true; +} + +void EncoderVorbis::loadSettings(){ + Settings *settings = Settings::self(); + + d->vorbis_encode_method = settings->vorbis_enc_method(); + d->vorbis_quality = settings->vorbis_quality(); + + if ( settings->set_vorbis_min_br()) { + d->vorbis_bitrate_lower = vorbis_bitrates[settings->vorbis_min_br()] * 1000; + } else { + d->vorbis_bitrate_lower = -1; + } + + if ( settings->set_vorbis_max_br() ) { + d->vorbis_bitrate_upper = vorbis_bitrates[settings->vorbis_max_br()] * 1000; + } else { + d->vorbis_bitrate_upper = -1; + } + + // this is such a hack! + if ( d->vorbis_bitrate_upper != -1 && d->vorbis_bitrate_lower != -1 ) { + d->vorbis_bitrate = 104000; // empirically determined ...?! + } else { + d->vorbis_bitrate = 160 * 1000; + } + + if ( settings->set_vorbis_nominal_br() ) { + d->vorbis_bitrate_nominal = vorbis_nominal_bitrates[settings->vorbis_nominal_br()] * 1000; + d->vorbis_bitrate = d->vorbis_bitrate_nominal; + } else { + d->vorbis_bitrate_nominal = -1; + } + + d->write_vorbis_comments = settings->vorbis_comments(); + + // Now that we have read in the settings apply them to the encoder lib + switch (d->vorbis_encode_method) { + case 0: +/* Support very old libvorbis by simply falling through. */ +#if HAVE_VORBIS >= 2 + vorbis_encode_init_vbr(&d->vi, 2, 44100, d->vorbis_quality/10.0); + break; +#endif + case 1: + vorbis_encode_init(&d->vi, 2, 44100, d->vorbis_bitrate_upper, d->vorbis_bitrate_nominal, d->vorbis_bitrate_lower); + break; + } + +} + +long EncoderVorbis::flush_vorbis(void) { + long processed(0); + + while(vorbis_analysis_blockout(&d->vd,&d->vb)==1) { + /* Support ancient libvorbis (< RC3). */ +#if HAVE_VORBIS >= 2 + vorbis_analysis(&d->vb,NULL); + /* Non-ancient case. */ + vorbis_bitrate_addblock(&d->vb); + + while(vorbis_bitrate_flushpacket(&d->vd, &d->op)) { +#else + vorbis_analysis(&d->vb,&d->op); + /* Make a lexical block to place the #ifdef's nearby. */ + if (1) { +#endif + ogg_stream_packetin(&d->os,&d->op); + while(int result=ogg_stream_pageout(&d->os,&d->og)) { + if (!result) break; + + TQByteArray output; + + char * oggheader = reinterpret_cast<char *>(d->og.header); + char * oggbody = reinterpret_cast<char *>(d->og.body); + + if (d->og.header_len) { + output.setRawData(oggheader, d->og.header_len); + ioslave->data(output); + output.resetRawData(oggheader, d->og.header_len); + } + + if (d->og.body_len) { + output.setRawData(oggbody, d->og.body_len); + ioslave->data(output); + output.resetRawData(oggbody, d->og.body_len); + } + processed += d->og.header_len + d->og.body_len; + } + } + } + return processed; +} + +unsigned long EncoderVorbis::size(long time_secs) const { + long vorbis_size; + switch (d->vorbis_encode_method) + { + case 0: // quality based encoding + +#if HAVE_VORBIS >= 2 // If really old Vorbis is being used, skip this nicely. + + { + // Estimated numbers based on the Vorbis FAQ: + // http://www.xiph.org/archives/vorbis-faq/200203/0030.html + + static long vorbis_q_bitrate[] = { 60, 74, 86, 106, 120, 152, + 183, 207, 239, 309, 440 }; + long quality = static_cast<long>(d->vorbis_quality); + if (quality < 0 || quality > 10) + quality = 3; + vorbis_size = (time_secs * vorbis_q_bitrate[quality] * 1000) / 8; + + break; + } + +#endif // HAVE_VORBIS >= 2 + + default: // bitrate based encoding + vorbis_size = (time_secs * d->vorbis_bitrate/8); + break; + } + + return vorbis_size; +} + +const char * EncoderVorbis::mimeType() const{ + return "audio/vorbis"; +} + +long EncoderVorbis::readInit(long /*size*/){ + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_init(&d->vd,&d->vi); + vorbis_block_init(&d->vd,&d->vb); + + srand(time(NULL)); + ogg_stream_init(&d->os,rand()); + + vorbis_analysis_headerout(&d->vd,&d->vc,&header,&header_comm,&header_code); + + ogg_stream_packetin(&d->os,&header); + ogg_stream_packetin(&d->os,&header_comm); + ogg_stream_packetin(&d->os,&header_code); + + while (int result = ogg_stream_flush(&d->os,&d->og)) { + + if (!result) break; + + TQByteArray output; + + char * oggheader = reinterpret_cast<char *>(d->og.header); + char * oggbody = reinterpret_cast<char *>(d->og.body); + + if (d->og.header_len) { + output.setRawData(oggheader, d->og.header_len); + ioslave->data(output); + output.resetRawData(oggheader, d->og.header_len); + } + + if (d->og.body_len) { + output.setRawData(oggbody, d->og.body_len); + ioslave->data(output); + output.resetRawData(oggbody, d->og.body_len); + } + } + return 0; +} + +long EncoderVorbis::read(int16_t * buf, int frames){ + int i; + float **buffer=vorbis_analysis_buffer(&d->vd,frames); + + /* uninterleave samples */ + for(i=0;i<frames;i++){ + buffer[0][i]=buf[2*i]/32768.0; + buffer[1][i]=buf[2*i+1]/32768.0; + } + + /* process chunk of data */ + vorbis_analysis_wrote(&d->vd,i); + return flush_vorbis(); +} + +long EncoderVorbis::readCleanup(){ + // send end-of-stream and flush the encoder + vorbis_analysis_wrote(&d->vd,0); + long processed = flush_vorbis(); + ogg_stream_clear(&d->os); + vorbis_block_clear(&d->vb); + vorbis_dsp_clear(&d->vd); + vorbis_info_clear(&d->vi); + return processed; +} + +void EncoderVorbis::fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ) +{ + if( !d->write_vorbis_comments ) + return; + + typedef TQPair<TQCString, TQVariant> CommentField; + TQValueList<CommentField> commentFields; + + commentFields.append(CommentField("title", info.trackInfoList[track].get("title"))); + commentFields.append(CommentField("artist", info.get("artist"))); + commentFields.append(CommentField("album", info.get("title"))); + commentFields.append(CommentField("genre", info.get("genre"))); + commentFields.append(CommentField("tracknumber", TQString::number(track+1))); + commentFields.append(CommentField("comment", comment)); + + if (info.get("year").toInt() > 0) { + TQDateTime dt(TQDate(info.get("year").toInt(), 1, 1)); + commentFields.append(CommentField("date", dt.toString(Qt::ISODate).utf8().data())); + } + + for(TQValueListIterator<CommentField> it = commentFields.begin(); it != commentFields.end(); ++it) { + + // if the value is not empty + if(!(*it).second.toString().isEmpty()) { + + char *key = tqstrdup((*it).first); + char *value = tqstrdup((*it).second.toString().utf8().data()); + + vorbis_comment_add_tag(&d->vc, key, value); + + delete [] key; + delete [] value; + } + } +} + +#endif // HAVE_VORBIS + diff --git a/tdeioslave/audiocd/plugins/vorbis/encodervorbis.h b/tdeioslave/audiocd/plugins/vorbis/encodervorbis.h new file mode 100644 index 00000000..ea6a0ac3 --- /dev/null +++ b/tdeioslave/audiocd/plugins/vorbis/encodervorbis.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef ENCODER_VORBIS_H +#define ENCODER_VORBIS_H + +#include <config.h> + +#ifdef HAVE_VORBIS + +#include <audiocdencoder.h> + +/** + * Ogg Vorbis encoder. + * This encoder is only enabled when HAVE_VORBIS is set. + * Check out http://www.vorbis.com/ for lots of information. + */ +class EncoderVorbis : public AudioCDEncoder { + +public: + EncoderVorbis(TDEIO::SlaveBase *slave); + ~EncoderVorbis(); + + virtual TQString type() const { return "Ogg Vorbis"; }; + virtual bool init(); + virtual void loadSettings(); + virtual unsigned long size(long time_secs) const; + virtual const char * fileType() const { return "ogg"; }; + virtual const char * mimeType() const; + virtual void fillSongInfo( KCDDB::CDInfo info, int track, const TQString &comment ); + virtual long readInit(long size); + virtual long read(int16_t * buf, int frames); + virtual long readCleanup(); + virtual TQWidget* getConfigureWidget(TDEConfigSkeleton** manager) const; + +private: + long flush_vorbis(); + + class Private; + Private * d; + +}; + +#endif // HAVE_VORBIS + +#endif // ENCODER_VORBIS_H + diff --git a/tdeioslave/audiocd/plugins/vorbis/encodervorbisconfig.ui b/tdeioslave/audiocd/plugins/vorbis/encodervorbisconfig.ui new file mode 100644 index 00000000..e442ade2 --- /dev/null +++ b/tdeioslave/audiocd/plugins/vorbis/encodervorbisconfig.ui @@ -0,0 +1,425 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>EncoderVorbisConfig</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>VorbisConfig</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>375</width> + <height>408</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQButtonGroup"> + <property name="name"> + <cstring>kcfg_vorbis_enc_method</cstring> + </property> + <property name="title"> + <string>&Encoding Method</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>vorbis_enc_quality</cstring> + </property> + <property name="text"> + <string>Quality based</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="TQRadioButton"> + <property name="name"> + <cstring>vorbis_enc_bitrate</cstring> + </property> + <property name="text"> + <string>Bitrate based</string> + </property> + </widget> + </hbox> + </widget> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>vorbis_bitrate_settings</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="title"> + <string>Vorbis Bitrate Settings</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>32 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>40 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>48 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>56 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>64 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>80 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>96 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>112 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>224 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>350 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_vorbis_min_br</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="currentItem"> + <number>1</number> + </property> + </widget> + <widget class="TQComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>32 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>40 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>48 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>56 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>64 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>80 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>96 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>112 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>224 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>350 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_vorbis_max_br</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="currentItem"> + <number>13</number> + </property> + </widget> + <widget class="TQCheckBox" row="0" column="0"> + <property name="name"> + <cstring>kcfg_set_vorbis_min_br</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>M&inimal bitrate:</string> + </property> + </widget> + <widget class="TQCheckBox" row="1" column="0"> + <property name="name"> + <cstring>kcfg_set_vorbis_max_br</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Ma&ximal bitrate:</string> + </property> + </widget> + <widget class="TQComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>128 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>160 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>192 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>256 kbs</string> + </property> + </item> + <item> + <property name="text"> + <string>350 kbs</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_vorbis_nominal_br</cstring> + </property> + <property name="currentItem"> + <number>1</number> + </property> + </widget> + <widget class="TQCheckBox" row="2" column="0"> + <property name="name"> + <cstring>kcfg_set_vorbis_nominal_br</cstring> + </property> + <property name="text"> + <string>A&verage bitrate:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>vorbis_quality_settings</cstring> + </property> + <property name="title"> + <string>Vorbis &Quality Setting</string> + </property> + <property name="whatsThis" stdset="0"> + <string>You can set the quality of the encoded stream here. A higher value implies a higher quality but encodes slower.</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KDoubleNumInput"> + <property name="name"> + <cstring>kcfg_vorbis_quality</cstring> + </property> + <property name="value"> + <number>0</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>10000</number> + </property> + <property name="precision"> + <number>1</number> + </property> + <property name="whatsThis" stdset="0"> + <string>Higher is better but slower</string> + </property> + </widget> + </hbox> + </widget> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>GroupBox193</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>kcfg_vorbis_comments</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Add &track information</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Add a description of the song to the file header. This makes it easy for the user to get advanced song information shown by his media player. You can get this information automatically via the Internet. Look at the <i>"CDDB Retrieval"</i> control module for details.</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>51</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<connections> + <connection> + <sender>vorbis_enc_bitrate</sender> + <signal>toggled(bool)</signal> + <receiver>vorbis_bitrate_settings</receiver> + <slot>setShown(bool)</slot> + </connection> + <connection> + <sender>vorbis_enc_quality</sender> + <signal>toggled(bool)</signal> + <receiver>vorbis_quality_settings</receiver> + <slot>setShown(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>vorbis_enc_quality</tabstop> + <tabstop>kcfg_set_vorbis_min_br</tabstop> + <tabstop>kcfg_set_vorbis_max_br</tabstop> + <tabstop>kcfg_set_vorbis_nominal_br</tabstop> + <tabstop>kcfg_vorbis_min_br</tabstop> + <tabstop>kcfg_vorbis_max_br</tabstop> + <tabstop>kcfg_vorbis_nominal_br</tabstop> + <tabstop>kcfg_vorbis_quality</tabstop> + <tabstop>kcfg_vorbis_comments</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/tdeioslave/audiocd/plugins/wav/Makefile.am b/tdeioslave/audiocd/plugins/wav/Makefile.am new file mode 100644 index 00000000..82e6ab28 --- /dev/null +++ b/tdeioslave/audiocd/plugins/wav/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/.. $(all_includes) + +INCLUDES = -I$(top_srcdir)/libkcddb + +kde_module_LTLIBRARIES = libaudiocd_encoder_wav.la + +libaudiocd_encoder_wav_la_SOURCES = encoderwav.cpp encodercda.cpp + +libaudiocd_encoder_wav_la_LIBADD = $(LIB_KIO) ../libaudiocdplugins.la $(CDPARANOIA_LIBS) + +libaudiocd_encoder_wav_la_LDFLAGS = -avoid-version -module -no-undefined $(all_libraries) + +pluginsdir = $(kde_datadir)/audiocd/plugins + +METASOURCES = AUTO diff --git a/tdeioslave/audiocd/plugins/wav/encodercda.cpp b/tdeioslave/audiocd/plugins/wav/encodercda.cpp new file mode 100644 index 00000000..ef8522d9 --- /dev/null +++ b/tdeioslave/audiocd/plugins/wav/encodercda.cpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "encodercda.h" + +class EncoderCda::Private +{ + public: + +}; + +unsigned long EncoderCda::size(long time_secs) const { + //return (time_secs * (44100 * 2 * 16))/8; + return (time_secs) * 176400; +} + +const char * EncoderCda::mimeType() const { + return "audio/x-cda"; +} + +// Remove this by calculating CD_FRAMESIZE_RAW from the frames +extern "C" +{ + #include <cdda_interface.h> +} + +inline int16_t swap16 (int16_t i) +{ + return (((i >> 8) & 0xFF) | ((i << 8) & 0xFF00)); +} + +long EncoderCda::read(int16_t * buf, int frames){ + TQByteArray output; + int16_t i16 = 1; + /* WAV is defined to be little endian, so we need to swap it + on big endian platforms. */ + if (((char*)&i16)[0] == 0) + for (int i=0; i < 2 * frames; i++) + buf[i] = swap16 (buf[i]); + char * cbuf = reinterpret_cast<char *>(buf); + output.setRawData(cbuf, CD_FRAMESIZE_RAW); + ioslave->data(output); + output.resetRawData(cbuf, CD_FRAMESIZE_RAW); + return CD_FRAMESIZE_RAW; +} + diff --git a/tdeioslave/audiocd/plugins/wav/encodercda.h b/tdeioslave/audiocd/plugins/wav/encodercda.h new file mode 100644 index 00000000..bb1297c7 --- /dev/null +++ b/tdeioslave/audiocd/plugins/wav/encodercda.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef ENCODER_CDA_H +#define ENCODER_CDA_H + +#include <audiocdencoder.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> + +/** + * Raw cd "encoder" + * Does little more then copy the data and make sure it is in the right + * endian. + */ +class EncoderCda : public AudioCDEncoder { + +public: + EncoderCda(TDEIO::SlaveBase *slave) : AudioCDEncoder(slave) {}; + ~EncoderCda(){}; + virtual bool init(){ return true; }; + virtual void loadSettings(){}; + virtual unsigned long size(long time_secs) const; + virtual TQString type() const { return "CDA"; }; + virtual const char * mimeType() const; + virtual const char * fileType() const { return "cda"; }; + virtual void fillSongInfo( KCDDB::CDInfo, int, const TQString &){}; + virtual long readInit(long){ return 0; }; + virtual long read(int16_t * buf, int frames); + virtual long readCleanup(){ return 0; }; + +private: + class Private; + Private * d; + +}; + +#endif // ENCODER_CDA_H + diff --git a/tdeioslave/audiocd/plugins/wav/encoderwav.cpp b/tdeioslave/audiocd/plugins/wav/encoderwav.cpp new file mode 100644 index 00000000..84a8586b --- /dev/null +++ b/tdeioslave/audiocd/plugins/wav/encoderwav.cpp @@ -0,0 +1,85 @@ +/* + Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "encoderwav.h" + +extern "C" +{ + KDE_EXPORT void create_audiocd_encoders(TDEIO::SlaveBase *slave, TQPtrList<AudioCDEncoder> &encoders) + { + encoders.append( new EncoderWav(slave)); + encoders.append( new EncoderCda(slave)); + } +} + +class EncoderWav::Private +{ + public: + +}; + +unsigned long EncoderWav::size(long time_secs) const { + return (EncoderCda::size(time_secs) + 44); +} + +const char * EncoderWav::mimeType() const { + return "audio/x-wav"; +} + +long EncoderWav::readInit(long byteCount){ + static char riffHeader[] = + { + 0x52, 0x49, 0x46, 0x46, // 0 "AIFF" + 0x00, 0x00, 0x00, 0x00, // 4 wavSize + 0x57, 0x41, 0x56, 0x45, // 8 "WAVE" + 0x66, 0x6d, 0x74, 0x20, // 12 "fmt " + 0x10, 0x00, 0x00, 0x00, // 16 + 0x01, 0x00, 0x02, 0x00, // 20 + 0x44, 0xac, 0x00, 0x00, // 24 + 0x10, 0xb1, 0x02, 0x00, // 28 + 0x04, 0x00, 0x10, 0x00, // 32 + 0x64, 0x61, 0x74, 0x61, // 36 "data" + 0x00, 0x00, 0x00, 0x00 // 40 byteCount + }; + + TQ_INT32 wavSize(byteCount + 44 - 8); + + + riffHeader[4] = (wavSize >> 0 ) & 0xff; + riffHeader[5] = (wavSize >> 8 ) & 0xff; + riffHeader[6] = (wavSize >> 16) & 0xff; + riffHeader[7] = (wavSize >> 24) & 0xff; + + riffHeader[40] = (byteCount >> 0 ) & 0xff; + riffHeader[41] = (byteCount >> 8 ) & 0xff; + riffHeader[42] = (byteCount >> 16) & 0xff; + riffHeader[43] = (byteCount >> 24) & 0xff; + + TQByteArray output; + output.setRawData(riffHeader, 44); + ioslave->data(output); + output.resetRawData(riffHeader, 44); + return 44; +} + diff --git a/tdeioslave/audiocd/plugins/wav/encoderwav.h b/tdeioslave/audiocd/plugins/wav/encoderwav.h new file mode 100644 index 00000000..154236f2 --- /dev/null +++ b/tdeioslave/audiocd/plugins/wav/encoderwav.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2000 Rik Hemsley (rikkus) <rik@kde.org> + Copyright (C) 2000, 2001, 2002 Michael Matz <matz@kde.org> + Copyright (C) 2001 Carsten Duvenhorst <duvenhorst@m2.uni-hannover.de> + Copyright (C) 2001 Adrian Schroeter <adrian@suse.de> + Copyright (C) 2003 Richard Lärkäng <richard@goteborg.utfors.se> + Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> + Copyright (C) 2004, 2005 Benjamin Meyer <ben at meyerhome dot net> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef ENCODER_WAV_H +#define ENCODER_WAV_H + +#include "encodercda.h" +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> + +/** + * Wav audio "encoder" + * Takes the CDA take and adds the standard wav header. + */ +class EncoderWav : public EncoderCda { + +public: + EncoderWav(TDEIO::SlaveBase *slave) : EncoderCda(slave) {}; + ~EncoderWav(){}; + virtual bool init(){ return true; }; + virtual unsigned long size(long time_secs) const; + virtual TQString type() const { return "Wav"; }; + virtual const char * fileType() const { return "wav"; }; + virtual const char * mimeType() const; + virtual void fillSongInfo( KCDDB::CDInfo, int, const TQString &){}; + virtual long readInit(long size); + +private: + class Private; + Private * d; + +}; + +#endif // ENCODER_WAV_H diff --git a/tdeioslave/audiocd/upgrade-metadata.sh b/tdeioslave/audiocd/upgrade-metadata.sh new file mode 100755 index 00000000..000323b1 --- /dev/null +++ b/tdeioslave/audiocd/upgrade-metadata.sh @@ -0,0 +1,28 @@ +#! /usr/bin/env bash + +while read; do + if [ "${REPLY#\[}" != "$REPLY" ] ; then # group name + GROUP="${REPLY:1:${#REPLY}-2}" + continue; + fi + # normal key=value pair: + KEY="${REPLY%%=*}" + VALUE="${REPLY#*=}" + + case "$GROUP/$KEY" in + FileName/file_name_template) + # + # Swap + # + VALUE=`echo $VALUE | sed -e s/%a/%{albumtitle}/g`; + VALUE=`echo $VALUE | sed -e s/%t/%{title}/g`; + VALUE=`echo $VALUE | sed -e s/%n/%{number}/g`; + VALUE=`echo $VALUE | sed -e s/%g/%{genre}/g`; + VALUE=`echo $VALUE | sed -e s/%y/%{year}/g`; + VALUE=`echo $VALUE | sed -e s/%A/%{albumartist}/g`; + echo "[FileName]"; + echo "file_name_template=$VALUE" + echo "# DELETE [FileName]file_name_template" + ;; + esac +done |