static int Open (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; demux_sys_t *sys = NULL; es_format_t fmt; bool result = false; SidTune *tune = NULL; sidplay2 *player = NULL; ReSIDBuilder *builder = NULL; int64_t size = stream_Size (demux->s); if (size < 4 || size > LONG_MAX) /* We need to load the whole file for sidplay */ return VLC_EGENERIC; const uint8_t *peek; if (vlc_stream_Peek (demux->s, &peek, 4) < 4) return VLC_EGENERIC; /* sidplay2 can read PSID and the newer RSID formats */ if(memcmp(peek,"PSID",4)!=0 && memcmp(peek,"RSID",4)!=0) return VLC_EGENERIC; uint8_t *data = (uint8_t*) malloc(size); if (unlikely (data==NULL)) goto error; if (vlc_stream_Read (demux->s,data,size) < size) { free (data); goto error; } tune = new (std::nothrow) SidTune(0); if (unlikely (tune==NULL)) { free (data); goto error; } result = tune->read (data, size); free (data); if (!result) goto error; player = new (std::nothrow) sidplay2(); if (unlikely(player==NULL)) goto error; sys = (demux_sys_t*) calloc (1, sizeof(demux_sys_t)); if (unlikely(sys==NULL)) goto error; sys->player = player; sys->tune = tune; tune->getInfo (sys->tuneInfo); sys->info = player->info(); sys->config = player->config(); builder = new (std::nothrow) ReSIDBuilder ("ReSID"); if (unlikely(builder==NULL)) goto error; builder->create (sys->info.maxsids); builder->sampling (sys->config.frequency); sys->config.sidEmulation = builder; sys->config.precision = 16; sys->config.playback = (sys->info.channels == 2 ? sid2_stereo : sid2_mono); player->config (sys->config); sys->bytes_per_frame = sys->info.channels * sys->config.precision / 8; sys->block_size = sys->config.frequency / 10 * sys->bytes_per_frame; es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_S16N); fmt.audio.i_channels = sys->info.channels; fmt.audio.i_bitspersample = sys->config.precision; fmt.audio.i_rate = sys->config.frequency; fmt.audio.i_bytes_per_frame = sys->bytes_per_frame; fmt.audio.i_frame_length = fmt.audio.i_bytes_per_frame; fmt.audio.i_blockalign = fmt.audio.i_bytes_per_frame; fmt.i_bitrate = fmt.audio.i_rate * fmt.audio.i_bytes_per_frame; sys->es = es_out_Add (demux->out, &fmt); date_Init (&sys->pts, fmt.audio.i_rate, 1); date_Set (&sys->pts, 0); sys->tune->selectSong (0); result = (sys->player->load (sys->tune) >=0 ); sys->player->fastForward (100); if (!result) goto error; /* Callbacks */ demux->pf_demux = Demux; demux->pf_control = Control; demux->p_sys = sys; return VLC_SUCCESS; error: msg_Err (demux, "An error occurred during sid demuxing" ); delete player; delete builder; delete tune; free (sys); return VLC_EGENERIC; }
extern "C" DB_playItem_t * csid_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { trace ("inserting %s\n", fname); sldb_load (); SidTune *tune; trace ("new SidTune\n"); tune = new SidTune (fname); int tunes = tune->getInfo ().songs; trace ("subtunes: %d\n", tunes); uint8_t sig[16]; unsigned char tmp[2]; #if 1 trace ("calculating md5\n"); DB_md5_t md5; deadbeef->md5_init (&md5); deadbeef->md5_append (&md5, (const uint8_t *)tune->cache.get () + tune->fileOffset, tune->getInfo ().c64dataLen); le_int16 (tune->getInfo ().initAddr, tmp); deadbeef->md5_append (&md5, tmp, 2); le_int16 (tune->getInfo ().playAddr, tmp); deadbeef->md5_append (&md5, tmp, 2); le_int16 (tune->getInfo ().songs, tmp); deadbeef->md5_append (&md5, tmp, 2); for (int s = 1; s <= tunes; s++) { tune->selectSong (s); // songspeed is uint8_t, so no need for byteswap deadbeef->md5_append (&md5, &tune->getInfo ().songSpeed, 1); } if (tune->getInfo ().clockSpeed == SIDTUNE_CLOCK_NTSC) { deadbeef->md5_append (&md5, &tune->getInfo ().clockSpeed, sizeof (tune->getInfo ().clockSpeed)); } deadbeef->md5_finish (&md5, sig); #else // md5 calc from libsidplay2 MD5 myMD5; myMD5.append ((const char *)tune->cache.get() + tune->fileOffset, tune->getInfo ().c64dataLen); // Include INIT and PLAY address. endian_little16 (tmp,tune->getInfo ().initAddr); myMD5.append (tmp,sizeof(tmp)); endian_little16 (tmp,tune->getInfo ().playAddr); myMD5.append (tmp,sizeof(tmp)); // Include number of songs. endian_little16 (tmp,tune->getInfo ().songs); myMD5.append (tmp,sizeof(tmp)); { // Include song speed for each song. for (uint_least16_t s = 1; s <= tune->getInfo ().songs; s++) { tune->selectSong (s); myMD5.append (&tune->getInfo ().songSpeed,1); } } // Deal with PSID v2NG clock speed flags: Let only NTSC // clock speed change the MD5 fingerprint. That way the // fingerprint of a PAL-speed sidtune in PSID v1, v2, and // PSID v2NG format is the same. if (tune->getInfo ().clockSpeed == SIDTUNE_CLOCK_NTSC) { myMD5.append (&tune->getInfo ().clockSpeed,sizeof(tune->getInfo ().clockSpeed)); } myMD5.finish (); memcpy (sig, myMD5.getDigest (), 16); #endif int song = -1; if (sldb_loaded) { song = sldb_find (sig); } trace ("inserting tunes...\n"); for (int s = 0; s < tunes; s++) { trace ("select %d...\n", s); if (tune->selectSong (s+1)) { DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, sid_plugin.plugin.id); deadbeef->pl_set_meta_int (it, ":TRACKNUM", s); SidTuneInfo sidinfo; tune->getInfo (sidinfo); int i = sidinfo.numberOfInfoStrings; int title_added = 0; trace ("set %d metainfo...\n", s); char temp[2048]; if (i >= 1 && sidinfo.infoString[0] && sidinfo.infoString[0][0]) { const char *meta; if (sidinfo.songs > 1) { meta = "album"; } else { meta = "title"; title_added = 1; } deadbeef->pl_add_meta (it, meta, convstr (sidinfo.infoString[0], strlen (sidinfo.infoString[0]), temp, sizeof (temp))); } if (i >= 2 && sidinfo.infoString[1] && sidinfo.infoString[1][0]) { deadbeef->pl_add_meta (it, "artist", convstr (sidinfo.infoString[1], strlen (sidinfo.infoString[1]), temp, sizeof (temp))); } if (i >= 3 && sidinfo.infoString[2] && sidinfo.infoString[2][0]) { deadbeef->pl_add_meta (it, "copyright", convstr (sidinfo.infoString[2], strlen (sidinfo.infoString[2]), temp, sizeof (temp))); } for (int j = 3; j < i; j++) { if (sidinfo.infoString[j] && sidinfo.infoString[j][0]) { deadbeef->pl_add_meta (it, "info", convstr (sidinfo.infoString[j], strlen (sidinfo.infoString[j]), temp, sizeof (temp))); } } char trk[10]; snprintf (trk, 10, "%d", s+1); deadbeef->pl_add_meta (it, "track", trk); if (!title_added) { deadbeef->pl_add_meta (it, "title", NULL); } float length = deadbeef->conf_get_float ("sid.defaultlength", 180); if (sldb_loaded) { if (song >= 0 && sldb->sldb_lengths[song][s] >= 0) { length = sldb->sldb_lengths[song][s]; } // if (song < 0) { // trace ("song %s not found in db, md5: ", fname); // for (int j = 0; j < 16; j++) { // trace ("%02x", (int)sig[j]); // } // trace ("\n"); // } } deadbeef->plt_set_item_duration (plt, it, length); deadbeef->pl_add_meta (it, ":FILETYPE", "SID"); after = deadbeef->plt_insert_item (plt, after, it); deadbeef->pl_item_unref (it); } } trace ("delete sidtune\n"); delete tune; return after; }
int __declspec(dllexport) DLL_GetNumberOfSongs(const char* szFileName) { SidTune tune; tune.load(szFileName,true); return tune.getInfo().songs; }
extern "C" DB_playItem_t * csid_insert (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname) { trace ("inserting %s\n", fname); find_hvsc_path_from_fname (fname); sldb_load (); SidTune *tune; trace ("new SidTune\n"); tune = new SidTune (fname); int tunes = tune->getInfo ().songs; trace ("subtunes: %d\n", tunes); uint8_t sig[16]; unsigned char tmp[2]; trace ("calculating md5\n"); DB_md5_t md5; deadbeef->md5_init (&md5); if (sldb_legacy) { deadbeef->md5_append (&md5, (const uint8_t *)tune->cache.get () + tune->fileOffset, tune->getInfo ().c64dataLen); le_int16 (tune->getInfo ().initAddr, tmp); deadbeef->md5_append (&md5, tmp, 2); le_int16 (tune->getInfo ().playAddr, tmp); deadbeef->md5_append (&md5, tmp, 2); le_int16 (tune->getInfo ().songs, tmp); deadbeef->md5_append (&md5, tmp, 2); for (int s = 1; s <= tunes; s++) { tune->selectSong (s); // songspeed is uint8_t, so no need for byteswap deadbeef->md5_append (&md5, &tune->getInfo ().songSpeed, 1); } if (tune->getInfo ().clockSpeed == SIDTUNE_CLOCK_NTSC) { deadbeef->md5_append (&md5, &tune->getInfo ().clockSpeed, sizeof (tune->getInfo ().clockSpeed)); } } else { deadbeef->md5_append (&md5, (const uint8_t *)tune->cache.get (), tune->getInfo ().dataFileLen); } deadbeef->md5_finish (&md5, sig); int song = -1; if (sldb_loaded) { song = sldb_find (sig); } trace ("inserting tunes...\n"); for (int s = 0; s < tunes; s++) { trace ("select %d...\n", s); if (tune->selectSong (s+1)) { DB_playItem_t *it = deadbeef->pl_item_alloc_init (fname, sid_plugin.plugin.id); deadbeef->pl_set_meta_int (it, ":TRACKNUM", s); SidTuneInfo sidinfo; tune->getInfo (sidinfo); int i = sidinfo.numberOfInfoStrings; int title_added = 0; trace ("set %d metainfo...\n", s); char temp[2048]; if (i >= 1 && sidinfo.infoString[0] && sidinfo.infoString[0][0]) { const char *meta; if (sidinfo.songs > 1) { meta = "album"; } else { meta = "title"; title_added = 1; } deadbeef->pl_add_meta (it, meta, convstr (sidinfo.infoString[0], strlen (sidinfo.infoString[0]), temp, sizeof (temp))); } if (i >= 2 && sidinfo.infoString[1] && sidinfo.infoString[1][0]) { deadbeef->pl_add_meta (it, "artist", convstr (sidinfo.infoString[1], strlen (sidinfo.infoString[1]), temp, sizeof (temp))); } if (i >= 3 && sidinfo.infoString[2] && sidinfo.infoString[2][0]) { deadbeef->pl_add_meta (it, "copyright", convstr (sidinfo.infoString[2], strlen (sidinfo.infoString[2]), temp, sizeof (temp))); } for (int j = 3; j < i; j++) { if (sidinfo.infoString[j] && sidinfo.infoString[j][0]) { deadbeef->pl_add_meta (it, "info", convstr (sidinfo.infoString[j], strlen (sidinfo.infoString[j]), temp, sizeof (temp))); } } char trk[10]; snprintf (trk, 10, "%d", s+1); deadbeef->pl_add_meta (it, "track", trk); if (!title_added) { deadbeef->pl_add_meta (it, "title", NULL); } float length = deadbeef->conf_get_float ("sid.defaultlength", 180); if (sldb_loaded && song >= 0 && s < sldb[song].subsongs) { uint16_t l = sldb_lengths[sldb[song].lengths_offset+s]; if (l >= 0) { length = l; } } deadbeef->plt_set_item_duration (plt, it, length); deadbeef->pl_add_meta (it, ":FILETYPE", "SID"); after = deadbeef->plt_insert_item (plt, after, it); deadbeef->pl_item_unref (it); } } trace ("delete sidtune\n"); delete tune; return after; }