/*---------------------------------------------------------------------------- libtunepimp -- The MusicBrainz tagging library. Let a thousand taggers bloom! Copyright (C) Robert Kaye 2003 This file is part of libtunepimp. libtunepimp 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. libtunepimp 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 libtunepimp; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $Id: tunepimp.xs 1367 2005-02-21 01:10:28Z robert $ ----------------------------------------------------------------------------*/ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include #include "const-c.inc" // Various "get string" functions require a buffer to be supplied, with no // obvious way to get the size of the buffer first. So let's guess high. #define BIG_STRING 1000 // Shorter buffers, for album type/status #define SMALL_STRING 100 // TRM length #define TRM_LENGTH 36 SV *perl_notify_callback = NULL; SV *perl_status_callback = NULL; void notify_callback(tunepimp_t o, void *data, TPCallbackEnum notifyType, int fileId, TPFileStatus status) { //if (notifyType == tpFileAdded) printf("TP notify callback: file #%d added\n", fileId); //else if (notifyType == tpFileChanged) printf("TP notify callback: file #%d changed\n", fileId); //else if (notifyType == tpFileRemoved) printf("TP notify callback: file #%d removed\n", fileId); //else printf("TP notify callback: file #%d unknown type #%d\n", fileId, notifyType); if (!perl_notify_callback) return; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSViv(notifyType))); XPUSHs(sv_2mortal(newSViv(fileId))); XPUSHs(sv_2mortal(newSViv(status))); PUTBACK; call_sv(SvRV(perl_notify_callback), G_VOID|G_DISCARD|G_EVAL); FREETMPS; LEAVE; } void status_callback(tunepimp_t o, void *data, const char *msg) { //printf("TP status callback: %s\n", msg); if (!perl_status_callback) return; //printf("time to call something in %s\n", CvFILE(SvRV(perl_status_callback))); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(msg, 0))); PUTBACK; call_sv(SvRV(perl_status_callback), G_VOID|G_DISCARD|G_EVAL); FREETMPS; LEAVE; } SV * _flatten_artist_result(artistresult_t *r) { HV *hv; hv = newHV(); hv_store(hv, "id", 2, newSVpv(r->id, 0), 0); hv_store(hv, "name", 4, newSVpv(r->name, 0), 0); hv_store(hv, "sortName", 8, newSVpv(r->sortName, 0), 0); hv_store(hv, "relevance", 9, newSViv(r->relevance), 0); return newRV_noinc((SV *)hv); } SV * _flatten_album_result(albumresult_t *r) { HV *hv; hv = newHV(); hv_store(hv, "id", 2, newSVpv(r->id, 0), 0); hv_store(hv, "name", 4, newSVpv(r->name, 0), 0); hv_store(hv, "relevance", 9, newSViv(r->relevance), 0); hv_store(hv, "numTracks", 9, newSViv(r->numTracks), 0); hv_store(hv, "numCDIndexIds", 13,newSViv(r->numCDIndexIds), 0); hv_store(hv, "isVA", 4, newSViv(r->isVA), 0); hv_store(hv, "isNA", 4, newSViv(r->isNA), 0); hv_store(hv, "status", 6, newSViv(r->status), 0); hv_store(hv, "type", 4, newSViv(r->type), 0); hv_store(hv, "artist", 6, _flatten_artist_result(&r->artist), 0); return newRV_noinc((SV *)hv); } SV * _flatten_track_result(albumtrackresult_t *r) { HV *hv; hv = newHV(); hv_store(hv, "relevance", 9, newSViv(r->relevance), 0); hv_store(hv, "name", 4, newSVpv(r->name, 0), 0); hv_store(hv, "id", 2, newSVpv(r->id, 0), 0); hv_store(hv, "numTRMIds", 9, newSViv(r->numTRMIds), 0); hv_store(hv, "trackNum", 8, newSViv(r->trackNum), 0); hv_store(hv, "duration", 8, newSVuv(r->duration), 0); hv_store(hv, "artist", 6, _flatten_artist_result(&r->artist), 0); hv_store(hv, "album", 5, _flatten_album_result(&r->album), 0); return newRV_noinc((SV *)hv); } MODULE = MusicBrainz::Tunepimp PACKAGE = MusicBrainz::Tunepimp # Yeah, there's bound to be a better way of doing this, but I don't know it, and # this method works. int TP_ARTIST_NAME_LEN() CODE: RETVAL = TP_ARTIST_NAME_LEN; OUTPUT: RETVAL int TP_ALBUM_NAME_LEN() CODE: RETVAL = TP_ALBUM_NAME_LEN; OUTPUT: RETVAL int TP_TRACK_NAME_LEN() CODE: RETVAL = TP_TRACK_NAME_LEN; OUTPUT: RETVAL int TP_ID_LEN() CODE: RETVAL = TP_ID_LEN; OUTPUT: RETVAL int TP_FORMAT_LEN() CODE: RETVAL = TP_FORMAT_LEN; OUTPUT: RETVAL int TP_COUNTRY_LEN() CODE: RETVAL = TP_COUNTRY_LEN; OUTPUT: RETVAL MODULE = MusicBrainz::Tunepimp::metadata PACKAGE = MusicBrainz::Tunepimp::metadata INCLUDE: const-xs.inc void clear(arg0) metadata_t * arg0 CODE: md_Clear(arg0); void _getAlbumStatusNameFromNumber(status) TPAlbumStatus status PREINIT: char albumStatus[SMALL_STRING]; CODE: md_ConvertFromAlbumStatus(status, albumStatus, SMALL_STRING); sp -= items; XPUSHs(sv_2mortal(newSVpv(albumStatus, 0))); XSRETURN(1); void _getAlbumTypeNameFromNumber(type) TPAlbumType type PREINIT: char albumType[SMALL_STRING]; CODE: md_ConvertFromAlbumType(type, albumType, SMALL_STRING); sp -= items; XPUSHs(sv_2mortal(newSVpv(albumType, 0))); XSRETURN(1); TPAlbumStatus _getAlbumStatusNumberFromName(albumStatus) const char * albumStatus CODE: RETVAL = md_ConvertToAlbumStatus(albumStatus); OUTPUT: RETVAL TPAlbumType _getAlbumTypeNumberFromName(albumType) const char * albumType CODE: RETVAL = md_ConvertToAlbumType(albumType); OUTPUT: RETVAL void DESTROY(arg0) metadata_t * arg0 CODE: md_Delete(arg0); metadata_t * _new() CODE: RETVAL = md_New(); OUTPUT: RETVAL # The following methods all read the members of the metadata_t struct char * getArtist(md) metadata_t * md CODE: if (!md->artist) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->artist, 0))); XSRETURN(1); char * getSortName(md) metadata_t * md CODE: if (!md->sortName) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->sortName, 0))); XSRETURN(1); char * getAlbum(md) metadata_t * md CODE: if (!md->album) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->album, 0))); XSRETURN(1); char * getTrack(md) metadata_t * md CODE: if (!md->track) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->track, 0))); XSRETURN(1); int getTrackNum(md) metadata_t * md CODE: RETVAL = md->trackNum; OUTPUT: RETVAL int getVariousArtist(md) metadata_t * md CODE: RETVAL = md->variousArtist; OUTPUT: RETVAL int getNonAlbum(md) metadata_t * md CODE: RETVAL = md->nonAlbum; OUTPUT: RETVAL char * getArtistId(md) metadata_t * md CODE: if (!md->artistId) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->artistId, 0))); XSRETURN(1); char * getAlbumId(md) metadata_t * md CODE: if (!md->albumId) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->albumId, 0))); XSRETURN(1); char * getTrackId(md) metadata_t * md CODE: if (!md->trackId) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->trackId, 0))); XSRETURN(1); char * getFileTrm(md) metadata_t * md CODE: if (!md->fileTrm) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->fileTrm, 0))); XSRETURN(1); char * getAlbumArtistId(md) metadata_t * md CODE: if (!md->albumArtistId) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->albumArtistId, 0))); XSRETURN(1); unsigned long getDuration(md) metadata_t * md CODE: RETVAL = md->duration; OUTPUT: RETVAL int getAlbumType(md) metadata_t * md CODE: RETVAL = md->albumType; OUTPUT: RETVAL char * getFileFormat(md) metadata_t * md CODE: if (!md->fileFormat[0]) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->fileFormat, 0))); XSRETURN(1); int getReleaseYear(md) metadata_t * md CODE: RETVAL = md->releaseYear; OUTPUT: RETVAL int getReleaseMonth(md) metadata_t * md CODE: RETVAL = md->releaseMonth; OUTPUT: RETVAL int getReleaseDay(md) metadata_t * md CODE: RETVAL = md->releaseDay; OUTPUT: RETVAL char * getReleaseCountry(md) metadata_t * md CODE: if (!md->releaseCountry[0]) XSRETURN_UNDEF; sp -= items; XPUSHs(sv_2mortal(newSVpv(md->releaseCountry, 0))); XSRETURN(1); int getNumTrmIds(md) metadata_t * md CODE: RETVAL = md->numTRMIds; OUTPUT: RETVAL void setArtist(md, artist) metadata_t * md const char *artist CODE: if (strlen(artist)+1 > TP_ARTIST_NAME_LEN) croak("artist name too long"); strncpy(md->artist, artist, TP_ARTIST_NAME_LEN); md->artist[TP_ARTIST_NAME_LEN] = '\0'; XSRETURN_UNDEF; void setSortName(md, sortName) metadata_t * md const char *sortName CODE: if (strlen(sortName)+1 > TP_ARTIST_NAME_LEN) croak("artist sortname too long"); strncpy(md->sortName, sortName, TP_ARTIST_NAME_LEN); md->sortName[TP_ARTIST_NAME_LEN] = '\0'; XSRETURN_UNDEF; void setAlbum(md, album) metadata_t * md const char *album CODE: if (strlen(album)+1 > TP_ALBUM_NAME_LEN) croak("album name too long"); strncpy(md->album, album, TP_ALBUM_NAME_LEN); md->album[TP_ALBUM_NAME_LEN] = '\0'; XSRETURN_UNDEF; void setTrack(md, track) metadata_t * md const char *track CODE: if (strlen(track)+1 > TP_TRACK_NAME_LEN) croak("track name too long"); strncpy(md->track, track, TP_TRACK_NAME_LEN); md->track[TP_TRACK_NAME_LEN] = '\0'; XSRETURN_UNDEF; void setTrackNum(md, trackNum) metadata_t * md int trackNum CODE: md->trackNum = trackNum; void setVariousArtist(md, variousArtist) metadata_t * md int variousArtist CODE: md->variousArtist = (variousArtist ? 1 : 0); void setNonAlbum(md, nonAlbum) metadata_t * md int nonAlbum CODE: md->nonAlbum = (nonAlbum ? 1 : 0); void setArtistId(md, artistId) metadata_t * md const char *artistId CODE: if (strlen(artistId)+1 > TP_ID_LEN) croak("artistId too long"); strncpy(md->artistId, artistId, TP_ID_LEN); md->artistId[TP_ID_LEN] = '\0'; XSRETURN_UNDEF; void setAlbumId(md, albumId) metadata_t * md const char *albumId CODE: if (strlen(albumId)+1 > TP_ID_LEN) croak("albumId too long"); strncpy(md->albumId, albumId, TP_ID_LEN); md->albumId[TP_ID_LEN] = '\0'; XSRETURN_UNDEF; void setTrackId(md, trackId) metadata_t * md const char *trackId CODE: if (strlen(trackId)+1 > TP_ID_LEN) croak("trackId too long"); strncpy(md->trackId, trackId, TP_ID_LEN); md->trackId[TP_ID_LEN] = '\0'; XSRETURN_UNDEF; void setFileTrm(md, fileTrm) metadata_t * md const char *fileTrm CODE: if (strlen(fileTrm)+1 > TP_ID_LEN) croak("fileTrm too long"); strncpy(md->fileTrm, fileTrm, TP_ID_LEN); md->fileTrm[TP_ID_LEN] = '\0'; XSRETURN_UNDEF; void setAlbumArtistId(md, albumArtistId) metadata_t * md const char *albumArtistId CODE: if (strlen(albumArtistId)+1 > TP_ID_LEN) croak("albumArtistId too long"); strncpy(md->albumArtistId, albumArtistId, TP_ID_LEN); md->albumArtistId[TP_ID_LEN] = '\0'; XSRETURN_UNDEF; void setDuration(md, duration) metadata_t * md unsigned long duration CODE: md->duration = duration; void setAlbumType(md, albumType) metadata_t * md TPAlbumType albumType CODE: md->albumType = albumType; # Note, no setters for these: # char * setFileFormat # int setReleaseYear # int setReleaseMonth # int setReleaseDay # char * setReleaseCountry # int setNumTRMIds int compare(mdA, mdB) metadata_t *mdA metadata_t *mdB CODE: RETVAL = md_Compare(mdA, mdB); OUTPUT: RETVAL MODULE = MusicBrainz::Tunepimp::tunepimp PACKAGE = MusicBrainz::Tunepimp::tunepimp INCLUDE: const-xs.inc int addFile(o, fileName, readMetadataNow) tunepimp_t o const char * fileName int readMetadataNow CODE: RETVAL = tp_AddFile(o, fileName, readMetadataNow); OUTPUT: RETVAL int addDir(o, dirPath) tunepimp_t o const char * dirPath CODE: RETVAL = tp_AddDir(o, dirPath); OUTPUT: RETVAL void DESTROY(o) tunepimp_t o CODE: tp_Delete(o); void getError(o) tunepimp_t o PREINIT: char error[BIG_STRING]; CODE: tp_GetError(o, error, BIG_STRING); sp -= items; XPUSHs(sv_2mortal(newSVpv(error, 0))); XSRETURN(1); void getFileIds(o) tunepimp_t o PREINIT: int * ids; int NumFileIds; int i; CODE: NumFileIds = tp_GetNumFileIds(o); if (!NumFileIds) XSRETURN_EMPTY; New(0, ids, NumFileIds, int); SAVEFREEPV(ids); tp_GetFileIds(o, ids, NumFileIds); sp -= items; EXTEND(SP, NumFileIds); for (i=0; i