Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: WavPack Lyrics (Read 10939 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

WavPack Lyrics

Hi All,

I thought I'd link to my post in FLAC http://www.hydrogenaudio.org/forums/index....showtopic=80465 as I'm not getting a lot of help and the FLAC developers seem to have disappeared I thought maybe the more lively WavPack community might be interested in my idea. It's not a 'new' idea, its just never actually been done and working like this before.

I'm fairly schooled in the theory behind FLAC and a little in WavPack, I'm just not a very good programming so I'm asking for help from anyone who might be able to help me get this running in ANY lossless format that current has no inbuilt Lyrics functionality, which pretty much narrows it down to FLAC and WavPack, as far as popular formats go.

I've always been a FLAC user but the source code is hard for me to understand, being a C beginner and having practically no comments on the examples/source code and nothing similar to base my work off. So if anyone in the WavPack community could help it would be much appreciated and if we can get it working in WavPack I might considering re-encoding all my FLAC library lol. And have a better look at the WavPack format.

I'm going to prepare another demo to try and show benefits of using a sub/rip format for Lyrics, hopefully with customizable fonts and colors. I'll post it up the next few days

WavPack Lyrics

Reply #1
I thought I'd link to my post in FLAC http://www.hydrogenaudio.org/forums/index....showtopic=80465


I tried the link in your first post (and some variants of it obviously), didn't seem to be able to download your file, sorry.
So, based on your other post, are you just looking for something which shows the correct lyrics corresponding to a time block (here are the lyrics for the next 5 seconds) or are you looking for more of a karaoke solution, highlighting where you are in the lyrics at that moment?
I certainly see ways this could be done with WavPack, for example if you had a new metadata sub-block (see http://www.wavpack.com/file_format.txt for existing ones). Obviously David would be the right person to allocate a new code (if he felt this idea had merit).
How were you planning on showing the lyrics (assuming the lyrics are contained within the WavPack files)? I didn't understand why you were referring to matroska files - if you were planning on embedding the lossless data in a matroska file, would it (the container) not be the best place to store the lyrics?


WavPack Lyrics

Reply #2
I tried the link in your first post (and some variants of it obviously), didn't seem to be able to download your file, sorry.
So, based on your other post, are you just looking for something which shows the correct lyrics corresponding to a time block (here are the lyrics for the next 5 seconds) or are you looking for more of a karaoke solution, highlighting where you are in the lyrics at that moment?
I certainly see ways this could be done with WavPack, for example if you had a new metadata sub-block (see http://www.wavpack.com/file_format.txt for existing ones). Obviously David would be the right person to allocate a new code (if he felt this idea had merit).
How were you planning on showing the lyrics (assuming the lyrics are contained within the WavPack files)? I didn't understand why you were referring to matroska files - if you were planning on embedding the lossless data in a matroska file, would it (the container) not be the best place to store the lyrics?


Hi soiaf, thanks for the quick reply, sorry I've been so busy lately and haven't responded.

In response to your questions. I'd like it to be similar to the first thing you said "shows the correct lyrics corresponding to a time block (here are the lyrics for the next 5 seconds)" but more customizable, certainly not like karaoke. I chose .SRT format originally because its easy and YouTube have been using this format for a while. Again the main reason is its pretty easy to implement. I've been working on another example that took me about 15-20 minutes to get this draft running. www mega uploads com/?d=5C91MU0K <-- fill in the spaces with dots as admin does not allow link to megauploads

The point of using the matroska files for demonstration is because you NEED video to show captions in every media player I know of (its the easiest way i know of anyway). So for demonstration purposes I used about 5 minutes of blank video, with a song Still Alive (.mp3 this time for space) and this .srt file which I knocked up quickly from the lyrics and running through the song pause/play and looking at the timecodes. just mkvmerge all that together and you have working subs with audio. More tweaking needs to be done to make this look perfect, but if you have Media Player Classic (a straight build from K Lite Codec Pack or otherwise) you should be able to play it, enable subtitles and it should work just to demonstrate how I would like it to.

"
1
00:00:00,000 --> 00:00:5,000
Lisa Miskovski - Still Alive
Lyrics by RickJames

2
00:00:20,000 --> 00:00:24,000
You have changed
I have changed

3
00:00:24,000 --> 00:00:30,000
Just like you
Just like you

4
00:00:30,000 --> 00:00:34,000
For how long
For how long

5
00:00:34,000 --> 00:00:38,000
Must I wait
I know there's something wrong

6
00:00:38,000 --> 00:00:43,000
Your concrete heart isn't beating

7
00:00:43,000 --> 00:00:47,000
And you tried to
Make it come alive

8
00:00:47,000 --> 00:00:50,000
No shadows

9
00:00:50,000 --> 00:00:56,000
Just red lights
Now I'm here to rescue you

10
00:01:04,000 --> 00:01:14,000
Oh I'm still alive
I'm still alive
I can not apologise no

11
00:01:22,000 --> 00:01:31,000
Oh I'm still alive
I'm still alive
I can not apologise no

12
00:01:31,000 --> 00:01:34,000
So silent

13
00:01:34,000 --> 00:01:36,000
No violence

14
00:01:36,000 --> 00:01:41,000
But inside my head
So loud and clear

15
00:01:41,000 --> 00:01:50,000
You're screaming
You're screaming
Cover up with a smile I've learned to fear

16
00:01:50,000 --> 00:01:54,000
Just sunshine
And blue sky

17
00:01:54,000 --> 00:01:59,000
That's just how it goes
For living here

18
00:01:59,000 --> 00:02:09,000
Come fire
Come fire
Let it burn and love come racing through

19
00:02:15,000 --> 00:02:25,000
Oh I'm still alive
I'm still alive
I can not apologise no

20
00:02:35,000 --> 00:02:44,000
Oh I'm still alive
I'm still alive
I can not apologise no

21
00:02:45,000 --> 00:02:52,000
Learn to lose
Learn to win
Turn my face against the wind

22
00:02:53,000 --> 00:03:02,000
I will move fast
I will move slow
Take me where I have to go

23
00:03:22,000 --> 00:03:24,000
(quiet) I'm still alive

24
00:03:28,000 --> 00:03:38,000
Oh I'm still alive
I'm still alive
I can not apologise no

25
00:03:41,000 --> 00:03:43,000
I'm still alive

26
00:03:47,000 --> 00:03:56,000
Oh I'm still alive
I'm still alive
I can not apologise no

27
00:04:04,000 --> 00:04:14,000
Oh I'm still alive
I'm still alive
I can not apologise no

28
00:04:14,000 --> 00:04:22,000
(fade out)

29
00:04:22,000 --> 00:04:32,000
Oh I'm still alive
I'm still alive
I can not apologise no
"

not the best song but it should be familiar to anyone who's played mirrors edge

I would like to show the lyrics through plugins through music players like foobar, winamp, etc. Ideally something like this is the foobar player http://picasaweb.google.com.au/lh/photo/Pt...feat=directlink again all this is open to interpretation.

as for the coding, I'd really like to fully understand it so if it works and there is reasonable interest we could bring it across to FLAC, MP3, AAC, etc. Another reason why I think this style of lyric might be useful is if indexing of the timecodes and lyrics was possible in the media player. Then you could just search for a phrase in the lyrics and play just that part of the song to see if you got the right song. For example if I searched for "You have changed" in my library and this song is in it, with the lyrics integrated, it would allow me to just play the 2 lines "You have changed I have changed" from 00:00:20,000 --> 00:00:24,000 in the song to see if it is the song I am looking for. Anyway I'm just throwing ideas around to justify why I think this might be useful in the future...

Thanks for the interest.

I'm working on another demo of a more recent song with a little rap, making it a little harder to sub and making it a little easier to understand by adding subs. I should finish that in the next few days for a repost. tell me if you have any problems with the download this time and also if anyone knows of somewhere better I could upload these demos.

WavPack Lyrics

Reply #3
Probably the easiest way to put something like this in WavPack files would be to add a text field to the APEv2 tag. No programming is required:

Code: [Select]
wavpack foo.wav -w "Lyrics=@foo.srt"

That would make them accessible to any program that needed them through the WavPack library API, or through another APEv2 tag reading library.

Since the .srt files are rather small, I would think that this would be fine for anything but the most memory-limited application. A much more complicated solution would be to embed the lyrics in pieces in the actual WavPack blocks using metadata (as soaif suggests) during the audio, but currently there is no API to either put these into WavPack files or retrieve them during playback (although this general capability is planned).

David

WavPack Lyrics

Reply #4
Thanks for the clarification!
As David says, the easiest way would be to just store the lyrics information in an APEv2 tag. Apart from the advantage that he mentions (no need to modify any WavPack code), you also have the advantage that any plugin you develop (say for foobar) would be pretty easy to modify to use other tag types/music files (like ID3 for MP3).
This would also have the advantage that it would be pretty quick for searching for lyrics within a song.

Going down the metadata approach that I previously mentioned is certainly possible, but a lot more work. Two ways I could see this being done off-hand
i) where you embed the lyrics information in the first block of the WavPack file
ii) where each block (or few blocks) of the file has the lyrics for the next few seconds of the song

The first solution really just gives you the same type of solution as using a APEv2 tag, but with more work and more problems
The second solution would be interesting, though it would need a lot more work. The media player plugin to use this would also be a lot more difficult to implement. This method would not be very suitable for quick searching for lyrics within a song.
I'd go with the APEv2 solution 

WavPack Lyrics

Reply #5
Probably the easiest way to put something like this in WavPack files would be to add a text field to the APEv2 tag. No programming is required:

Code: [Select]
wavpack foo.wav -w "Lyrics=@foo.srt"

That would make them accessible to any program that needed them through the WavPack library API, or through another APEv2 tag reading library.

Since the .srt files are rather small, I would think that this would be fine for anything but the most memory-limited application. A much more complicated solution would be to embed the lyrics in pieces in the actual WavPack blocks using metadata (as soaif suggests) during the audio, but currently there is no API to either put these into WavPack files or retrieve them during playback (although this general capability is planned).

David


Awesome work! Thanks guys, that works as expected, now I've just got to get a very basic foobar or winamp plugin working and I'll be happy. I'm wondering how to get good at programming, I know JAVA, basic C, C++, SQL, PHP and a few other languages all taught through university. But the most were little command like assignments, data structures, txt and file manipulation. Everything I see out there like FLAC coding, winamp and foobar plugins for example is on another level! I don't know what the next step is to get a better understanding and also whenever I say "Oh I know, I'll program something to do this", it's already been done better or something similar with the same outcome, so I just don't bother. I'm so busy with school, etc. I never have time to do personal projects so I just rely on others for help. Sorry, this is probably getting a little morbid, I've pretty much made up my mind I don't want to be a programmer I'm much better at Database, Server, Network, Windows, Unix setup and management, etc. I just find it odd that I'm coming towards the end of my university learning (which I have passed everything with reasonable marks) and haven't been taught how to program a basic win32 application or any real gui application for that matter. I mean I dabbled with VB in high school but I'm beginning to feel more and more like you have to be some sort of boy genius to really get into programming...

Anyway if there are any good programming books out there that you know of, I tend to prefer things with lots of example, then please let me know. As for now I'm going to post something on the foobar and possibly winamp boards asking where to get started with this plugin. Thanks guys again for all your help!

WavPack Lyrics

Reply #6
The only way I know to get better at programming is to program in your spare time working on things that you find interesting. When I work on bigger projects I like to get something simple working and then build on that, instead of trying to get the whole thing written and then trying to figure out whats broken
So, you mention that you've done text and file manipulation, maybe the first thing to do is to write a program that reads an SRT file and just print the lyrics, then the follow up is have a command line program that reads the timing and prints the correct lyrics at the right time (as if it was showing the lyrics at the correct time in the song, but without the music!).
As David says, the easiest way to read tag information from a WavPack file is using the WavPack library API, this is pretty straightforward to use, if you want to see an example of it being used to read tag information from a WavPack file, have a look at this example from the code for WavPack support on Android devices

https://review.source.android.com/#patch,si...ediaScanner.cpp

I've also written code to read tags from WavPack files in a few different languages (not using the API), theres no problem doing that, but its easier/quicker to use the library API (though your code may be a bit bigger).
I haven't written a foobar plugin, but I know theres sample code. Try getting one of the samples and just compiling it and making it work, then just build on that.
And if you get stuck with any of the WavPack code, just post here and I'll try to help

WavPack Lyrics

Reply #7
Thanks soiaf,
I've started a REAL basic program that just outputs the .srt contents to screen (only took me a few minutes, I'm not THAT bad lol). Now I'm wondering weather I should interpret the text as lyric objects or something like that... Maybe It'll make it easier later on. But I'll have a play around and see how I go. Also the way I could see the timed lyrics working is 1. build a timer within the program (probably the better way) or 2. Go off system time. Either way I haven't done anything like that in C++ as of yet.

Anyways, the main reason for my post is I synced some more lyrics with the aid of "Subtitle Workshop" which made it real easy. Took me maybe 20minutes to get this next song's lyrics looking good even though it was much more complex http://www.megaupload<DOT>com/?d=565K9YMV . I also wanted to say I made a quick post on the foobar/developer forums so we'll see how that goes. Enjoy!

Thanks for the interest again. I know it seems like a silly project but It's a neat concept to me and I think it would be a real credit to audio formats.

WavPack Lyrics

Reply #8
Whatever way you go with the timer, remember to keep your ultimate end goal in sight (media player support for showing lyrics) so you'll want to make sure your model would support features like seeking, so if the person jumps to the middle of the song, you show the correct lyrics for that time.

Good luck with your coding, its sounds like a neat idea. Maybe as a follow-up prject (or a parallel one) you could make a program/addon to enable people to make their own 'timed' lyrics. Its straightforward enough to get lyrics for most songs, but not in the format you need it in. And you would be able to use the WavPack library API to write the tags to a file.

WavPack Lyrics

Reply #9
hi guys,

still trying to work out how time.h and a timer might work in this case, just thought I'd post my simple little code for reading .srt files, maybe you could go though it and give me some tips.

lyrics.h
Code: [Select]
#ifndef LYRIC_H
#define LYRIC_H

#include <string>
#include <time.h>
#include <fstream>
#include <iostream>
#include <stdio.h>

using namespace std;

class lyric
{
public:
    lyric(int lid, string stime, string ftime, string lines);
    lyric();

    //gets
    int Lid() { return lid; }
    string Stime() { return stime; }  //start time & end time are just strings for the moment
    string Ftime() { return ftime; }   //until I work out what I need to get the timer working
    string Lines() { return lines; }

    friend ostream& operator<< (ostream &out, lyric &clyric);
    
private:
    int lid;
    string stime;
    string ftime;
    string lines;
};

#endif


lyrics.cpp
Code: [Select]
#include "lyric.h"

lyric::lyric(int lid, string stime, string ftime, string lines)
{
    this->lid = lid;
    this->stime = stime;
    this->ftime = ftime;
    this->lines = lines;
}

lyric::lyric()
{

}

ostream& operator<< (ostream &out, lyric &clyric)
{
    // Since operator<< is a friend of the Point class, we can access
    // Point's members directly.
    out << "(" << clyric.lid << ", " <<
        clyric.stime << ", " <<
        clyric.ftime << ", " <<
        clyric.lines << ")";
    return out;
}


srtreader.cpp
Code: [Select]
#include "lyric.h"

using namespace std;

int main ()
{
    int lid, max;
    string line, line2, lyrics;
    lyric* slyrics;

    ifstream myfile("Lyrics.srt", ifstream::in); //open lyrics

    if (myfile.is_open())
    {
        while (! myfile.eof() ) //counts the number of lyrics
        {
            getline(myfile, line);
            lid = atoi(line.c_str()); //lyric id
            while (myfile.eof() == 0 && line.length() != 0) //lyrics
            {
                getline(myfile,line);
                lyrics += line;
            }
        }
        max = lid; //last lyric ID is the max number of lyrics

        myfile.close();                                //these 2 lines are reseting the fstream to the start
        myfile.open("Lyrics.srt", ifstream::in);    //I'm sure there is a better way to do this

        slyrics = new lyric[max];

        for (int i=0;! myfile.eof();i++ )
        {
            getline(myfile, line);
            lid = atoi(line.c_str()); //lyric id

            getline(myfile,line2); //<start time> --> <end time>

            lyrics.clear();
            while (myfile.eof() != 1 && line.length() != 0) //find all the lyic lines and add dynamically
            {
                getline(myfile,line); //lyrics
                lyrics += (line + '\n');
                    //cout << "lyrics: " << line << "\n";
            }
            
            while (lyrics.find_last_of('\n') == (lyrics.length()-1)) //trim function
            {
                lyrics = lyrics.substr(0,lyrics.length()-1);
            }

            slyrics[i] = lyric(lid,line2.substr(0,12),line2.substr(17,29),lyrics);
        }
        myfile.close();

        for (int i=0;i < max;++i) //print lyric objects
        {
            cout << slyrics[i] << endl;
        }
    }
    else
    {
        cout << "Unable to open file";
    }

    cin >> line;
    
    return 0;
}


I've been dreading the idea that maybe I need another thread to do the timer... I have a bit of time in the next week or so to work on it, so I'll keep checking back if you guys have any suggestions
Thanks

WavPack Lyrics

Reply #10
I'll try to have a look at your code sometime over the next couple of days. I can see one thing straightaway though.

Where you have

Code: [Select]
        myfile.close();                                //these 2 lines are reseting the fstream to the start
        myfile.open("Lyrics.srt", ifstream::in);    //I'm sure there is a better way to do this


you could replace this with

Code: [Select]
         myfile.clear();
         myfile.seekg(0);


The other thing I see is that the code looks like it assumes that the SRT data is correctly formatted, obviously this should be the case, but some error handling is always good!

WavPack Lyrics

Reply #11
SUCCESS! Well at least partially anyway, it now prints them out at the right time approximately anyway.

I need some help with the exceptions and getting it to actually read from the WavPack tags but once that's done I should be able to post a little more information to my neglected foobar post, hopefully someone there will see this project isn't completely hopeless and give me an idea about how to start a foobar component....

lyric.h
Code: [Select]
#ifndef LYRIC_H
#define LYRIC_H

#include <string>
#include <time.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <time.h>

using namespace std;

class lyric
{
public:
    lyric(int lid, string stime, string ftime, string lines);
    lyric();

    //gets
    int Lid() { return lid; }
    string Stime() { return stime; }
    string Ftime() { return ftime; }
    string Lines() { return lines; }
    int stm() { return st; }
    int ftm() { return ft; }
    int Duration() { return duration; }

    friend ostream& operator<< (ostream &out, lyric &clyric);
    
private:
    int lid;
    string stime;
    string ftime;
    string lines;
    int st; //start time in milliseconds
    int ft; //finished time in milliseconds
    int duration; //in milliseconds
};

#endif


lyrics.cpp
Code: [Select]
#include "lyric.h"

lyric::lyric(int lid, string stime, string ftime, string lines)
{
    char *str1,*str2, *token1,*token2, *next_token1, *next_token2;
    char seps[]   = " :,";

    this->lid = lid;
    this->stime = stime;
    this->ftime = ftime;
    this->lines = lines;

    st = 0;
    ft = 0;

    str1 = new char[stime.size()+1];
    strcpy_s(str1,stime.size()+1,stime.c_str());

    str2 = new char[ftime.size()+1];
    strcpy_s(str2,ftime.size()+1,ftime.c_str());

    token1 = strtok_s( str1, seps, &next_token1);
    st += atoi(token1)*3600000;    //hours

    if (token1 != NULL)
    {
        token1 = strtok_s( NULL, seps, &next_token1);
        st += atoi(token1)*60000;        //minutes
    }

    if (token1 != NULL)
    {
        token1 = strtok_s( NULL, seps, &next_token1);
        st += atoi(token1)*1000;        //seconds
    }

    if (token1 != NULL)
    {
        token1 = strtok_s( NULL, seps, &next_token1);
        st += atoi(token1);            //milliseconds
    }

    token2 = strtok_s( str2, seps, &next_token2);
    ft += atoi(token2)*3600000;    //hours

    if (token2 != NULL)
    {
        token2 = strtok_s (NULL, seps, &next_token2);
        ft += atoi(token2)*60000;        //minutes
    }

    if (token2 != NULL)
    {
        token2 = strtok_s (NULL, seps, &next_token2);
        ft += atoi(token2)*1000;        //seconds
    }

    if (token2 != NULL)
    {
        token2 = strtok_s (NULL, seps, &next_token2);
        ft += atoi(token2);            //milliseconds
    }

    //IF st > ft throw exception @ lyric number 'lid' exit(1)
    this->duration = ft - st;
}

lyric::lyric()
{

}

ostream& operator<< (ostream &out, lyric &clyric)
{
    out << "(" << clyric.lid << ", Start time: " <<
        clyric.st <<", Finish time: " <<  clyric.ft << ")";
    return out;
}


srtreader.cpp (driver)
Code: [Select]
#include "lyric.h"

using namespace std;

void wait ( int ms );

int main ()
{
    int lid, max, ctime;
    string line, line2, lyrics;
    lyric* slyrics;

    ifstream myfile("Lyrics.srt", ifstream::in); //open lyrics !needs to be changed to read from wavpack tag marked with extention *.srt

    if (myfile.is_open())
    {
        while (! myfile.eof() ) //counts the number of lyrics
        {
            getline(myfile, line);
            lid = atoi(line.c_str()); //lyric id !Throw 'not correct format' "exception at this line x =" exit(1)
            while (myfile.eof() == 0 && line.length() != 0) //lyrics
            {
                getline(myfile,line);
                lyrics += line;
            }
        }
        max = lid; //last lyric ID is the max number of lyrics

        myfile.clear();
                myfile.seekg(0);

        slyrics = new lyric[max];

        for (int i=0;! myfile.eof();i++ )
        {
            getline(myfile, line);
            lid = atoi(line.c_str()); //lyric id //exception taken care of from the last while loop

            getline(myfile,line2); //<start time> --> <end time> !IF line2.size() != 29 Throw 'not correct format' "exception at this line x =" exit(1)

            lyrics.clear();
            while (myfile.eof() != 1 && line.length() != 0) //find all the lyric lines and add dynamically
            {
                getline(myfile,line); //lyrics
                lyrics += (line + '\n');
            }
            
            while (lyrics.find_last_of('\n') == (lyrics.length()-1)) //trim function
            {
                lyrics = lyrics.substr(0,lyrics.length()-1);
            }

            slyrics[i] = lyric(lid,line2.substr(0,12),line2.substr(17,29),lyrics);
        }
        myfile.close();

        ctime = 0;

        for (int i=0;i < max;++i) //print lyric objects
        {
            if (slyrics[i].stm()-ctime > 10)
            {
                wait(slyrics[i].stm()-ctime);
            }
            cout << slyrics[i].Lines() << endl;
            wait(slyrics[i].Duration() - 125);    //this offset is just a guess, wait isn't accurate, well for me anyway
            system( "cls" );
            ctime = slyrics[i].ftm();
        }
    }
    else
    {
        cout << "Unable to open file";
    }

    cin >> line;
    
    return 0;
}

void wait ( int ms )
{
    clock_t endwait;
    endwait = clock () + ms;
    while (clock() < endwait) {}
}


soiaf maybe if you could help me with the exceptions, thank you in advance!
And maybe your friend bryant or yourself could see about what I need to do to in-from-wavpack file with *.srt lyrics tag?

I'm busy for the next few days with other work, so I'll leave it as is until I hear from you, thanks again.

WavPack Lyrics

Reply #12
Unfortunately I can't compile your code as you're using some Microsoft specific calls i.e. strcpy_s and strtok_s. These may be available in some other compiler environments, but not in mine (Ubuntu g++).

Anyway, looking at the code theres a couple of things I can point out.
In srtreader.cpp, when you're reading in the number of lyrics 'chunks', you have the line

Code: [Select]
lid = atoi(line.c_str()); //lyric id !Throw 'not correct format' "exception at this line x =" exit(1)


atoi does not throw an exception. If you give it a string that does not have an integer, it will simply return 0.
This could then cause a problem later in your code, if theres an error in the data towards the very end of the code, then atoi would return 0. You would then set the value of 'max' to be 0, and declare slyrics to be an array of zero size.

You would then find that this line would cause a failure

Code: [Select]
slyrics[i] = lyric(lid,line2.substr(0,12),line2.substr(17,29),lyrics);


To actually read data from a WavPack file, you'll need the WavPack source code, obviously available on http://www.wavpack.com

In this package theres a number of directories, the main ones of interest to you are the src and include directories. You'll need to add the various C source files to your source directory (theres more files than you need, but lets assume you need them all to start with).

Now, as your code is C++, you'll need to declare the following in your code

Code: [Select]
extern "C" {  
#include "wavpack.h"  
}



Now, because you'll eventually be working from a plugin, I think you'll want finer control of the actual file handling routines, but the following should work fine for you

Code: [Select]
// Needed for WavPack functions   
#include <sys/types.h>  
#include <sys/stat.h>  
#include <unistd.h>  
    
      
  static int32_t read_bytes (void *id, void *data, int32_t bcount) {  
      return (int32_t) fread (data, 1, bcount, (FILE*) id);  
   }  
    
  static uint32_t get_pos (void *id) {  
       return ftell ((FILE*) id);  
  }  
    
  static int set_pos_abs (void *id, uint32_t pos) {  
      return fseek ((FILE *)id, pos, SEEK_SET);  
  }  
    
  static int set_pos_rel (void *id, int32_t delta, int mode) {  
      return fseek ((FILE *)id, delta, mode);  
  }  
    
  static int push_back_byte (void *id, int c) {  
      return ungetc (c, (FILE *)id);  
  }  
    
  static uint32_t get_length (void *id) {  
      FILE *file = (FILE *)id;  
      struct stat statbuf;  
    
      if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG))  
          return 0;  
    
       return statbuf.st_size;  
   }  
    
  static int can_seek (void *id) {  
      FILE *file = (FILE *)id;  
      struct stat statbuf;  
    
      return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG);  
  }  
    
  static int32_t write_bytes (void *id, void *data, int32_t bcount) {  
      return (int32_t) fwrite (data, 1, bcount, (FILE*) id);  
  }  
    
  static WavpackStreamReader freader = {  
      read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte, get_length, can_seek,  
      write_bytes  
  };



Now after this you need to actually read the tag information, thiis isn't the full code, but you should get the idea from this.

Code: [Select]
WavpackContext *wpc;
int open_flags;
int srt_size;
int retval;
char errorBuff[128];
FILE *f = NULL

f = fopen("somewavpackfile.wv", "r");  
if (!f)
{
// something really bad has happened, you can't open the file, maybe time to quit
}  

open_flags = OPEN_TAGS | OPEN_2CH_MAX | OPEN_NORMALIZE;

wpc = WavpackOpenFileInputEx (&freader, f, NULL, errorBuff, open_flags, 0);

if (wpc == NULL) {
// not good, time to exit
}

// work out if there is Lyrics data, this will return the size of the Lyrics tag or 0 if not there
srt_size = WavpackGetTagItem (wpc, "Lyrics", NULL, 0);


// this is rough code, remember you need to check that the malloc worked
char *srtdata = (char*)malloc(srt_size);

retval = WavpackGetTagItem (wpc, "Lyrics", srtdata, srt_size);

wpc = WavpackCloseFile(wpc);  // tidies up after us

// Lyrics data is now is srtdata, process this as you like.....

// don't forget to free the memory you grabbed after you've processed the SRT data

free(srtdata);


This should be everything you need to know. To understand more about the tag reading code, read the comments in the wputils.c file (one of the WavPack files).

WavPack Lyrics

Reply #13
I should have replied sooner,

Firstly the strcpy_s and strtok_s are just microsoft replacements for those functions. It was annoyed at getting 10+ warnings every time I compiled, so I changed it, but they can be changed back.

I tried adding in the bits of code for reading the tags, but when I add the line.

Code: [Select]
wpc = WavpackOpenFileInputEx (&freader, f, NULL, errorBuff, open_flags, 0);


I get these errors

Quote
1>srtreader.obj : error LNK2028: unresolved token (0A0003EB) "extern "C" void * __cdecl WavpackOpenFileInputEx(struct WavpackStreamReader *,void *,void *,char *,int,int)" (?WavpackOpenFileInputEx@@$$J0YAPAXPAUWavpackStreamReader@@PAX1PADHH@Z) referenced in function "int __cdecl main(void)" (?main@@$$HYAHXZ)
1>srtreader.obj : error LNK2019: unresolved external symbol "extern "C" void * __cdecl WavpackOpenFileInputEx(struct WavpackStreamReader *,void *,void *,char *,int,int)" (?WavpackOpenFileInputEx@@$$J0YAPAXPAUWavpackStreamReader@@PAX1PADHH@Z) referenced in function "int __cdecl main(void)" (?main@@$$HYAHXZ)


Have you had any further success?

WavPack Lyrics

Reply #14
Ok, the error you're getting is a linker error. Two possibilities immediately come to mind

1) That you've included the WavPack source code directly in your SRT reader code base, and its treating the source code as C++ code. If this is the case then the solution is to change

Code: [Select]
extern "C" {  
#include "wavpack.h"  
}


to just

Code: [Select]
#include "wavpack.h"


2) Your code is not seeing the wputils.c file, in which case you need to ensure that you add this file to your project.

Unfortunately I haven't had a chance to look at your code more, I ran into a problem when I was upgrading the OS on my development machine and it'll take me another few days to fix that and get back up and running again. When I'm going again I'll look at your code then.

WavPack Lyrics

Reply #15
Hey soiaf

I tried your suggestion, it didn't want to work with extern or without, so I had to add ALL The wavpack src as "Resource Files" and set them to compile without /clr (I don't know why) but after that it actually compiled. I changed the _s (safe methods back) so hopefully it might work on your compiler as is. Here is the current code

lyric.h

Code: [Select]
#ifndef LYRIC_H
#define LYRIC_H

extern "C" {
#include "include\wavpack.h"
}

#include <string>
#include <fstream>
#include <iostream>
//#include <stdio.h>
#include <time.h>
//#include <sys/types.h>
#include <sys/stat.h>

using namespace std;

class lyric
{
public:
    lyric(int lid, string stime, string ftime, string lines);
    lyric();

    //gets
    int Lid() { return lid; }
    string Stime() { return stime; }
    string Ftime() { return ftime; }
    string Lines() { return lines; }
    int stm() { return st; }
    int ftm() { return ft; }
    int Duration() { return duration; }

    friend ostream& operator<< (ostream &out, lyric &clyric);
    
private:
    int lid;
    string stime;
    string ftime;
    string lines;
    int st; //start time in milliseconds
    int ft; //finished time in milliseconds
    int duration; //in milliseconds
};

#endif


lyrics.cpp
Code: [Select]
#include "lyric.h"

lyric::lyric(int lid, string stime, string ftime, string lines)
{
    char *str1,*str2, *token1,*token2, *next_token1, *next_token2;
    char seps[]   = " :,";

    this->lid = lid;
    this->stime = stime;
    this->ftime = ftime;
    this->lines = lines;

    st = 0;
    ft = 0;

    str1 = new char[stime.size()+1];
    strcpy(str1,stime.c_str());

    str2 = new char[ftime.size()+1];
    strcpy(str2,ftime.c_str());

    token1 = strtok(str1, seps);
    st += atoi(token1)*3600000;    //hours

    if (token1 != NULL)
    {
        token1 = strtok( NULL, seps);
        st += atoi(token1)*60000;        //minutes
    }

    if (token1 != NULL)
    {
        token1 = strtok ( NULL, seps);
        st += atoi(token1)*1000;        //seconds
    }

    if (token1 != NULL)
    {
        token1 = strtok ( NULL, seps);
        st += atoi(token1);            //milliseconds
    }

    token2 = strtok ( str2, seps);
    ft += atoi(token2)*3600000;    //hours

    if (token2 != NULL)
    {
        token2 = strtok (NULL, seps);
        ft += atoi(token2)*60000;        //minutes
    }

    if (token2 != NULL)
    {
        token2 = strtok (NULL, seps);
        ft += atoi(token2)*1000;        //seconds
    }

    if (token2 != NULL)
    {
        token2 = strtok (NULL, seps);
        ft += atoi(token2);            //milliseconds
    }

    //IF st > ft throw exception @ lyric number 'lid' exit(1)
    this->duration = ft - st;
}

lyric::lyric()
{

}

ostream& operator<< (ostream &out, lyric &clyric)
{
    out << "(" << clyric.lid << ", Start time: " <<
        clyric.st <<", Finish time: " <<  clyric.ft << ")";
    return out;
}


srtreader.cpp
Code: [Select]
#include "lyric.h"

void wait ( int ms );

static int32_t read_bytes (void *id, void *data, int32_t bcount) {  
      return (int32_t) fread (data, 1, bcount, (FILE*) id);  
   }  
    
  static uint32_t get_pos (void *id) {  
       return ftell ((FILE*) id);  
  }  
    
  static int set_pos_abs (void *id, uint32_t pos) {  
      return fseek ((FILE *)id, pos, SEEK_SET);  
  }  
    
  static int set_pos_rel (void *id, int32_t delta, int mode) {  
      return fseek ((FILE *)id, delta, mode);  
  }  
    
  static int push_back_byte (void *id, int c) {  
      return ungetc (c, (FILE *)id);  
  }  
    
  static uint32_t get_length (void *id) {  
      FILE *file = (FILE *)id;  
      struct stat statbuf;  
    
      if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG))  
          return 0;  
    
       return statbuf.st_size;  
   }  
    
  static int can_seek (void *id) {  
      FILE *file = (FILE *)id;  
      struct stat statbuf;  
    
      return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG);  
  }  
    
  static int32_t write_bytes (void *id, void *data, int32_t bcount) {  
      return (int32_t) fwrite (data, 1, bcount, (FILE*) id);  
  }  
    
  static WavpackStreamReader freader = {  
      read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte, get_length, can_seek,  
      write_bytes  
  };

int main ()
{
    WavpackContext *wpc;
    int open_flags;
    int srt_size;
    int retval;
    char errorBuff[128];
    FILE *f = NULL;

    int lid, max, ctime, error;
    string line, line2, lyrics;
    lyric* slyrics;

    f = fopen("Love The Way You Lie.wv", "r");  
    if (!f)
    {
        cout << "Error! couldn't open wavpack file" << endl;
        cin >> lid;
        exit(1);
        // something really bad has happened, you can't open the file, maybe time to quit
    }

    open_flags = OPEN_TAGS | OPEN_2CH_MAX | OPEN_NORMALIZE;

    wpc = WavpackOpenFileInputEx (&freader, f, NULL, errorBuff, open_flags, 0);

    if (wpc == NULL) //currently always true
    {
        cout << "Error! inside wavpack file" << endl;
        cin >> lid;
        exit(1);
    }

    /*
    // work out if there is Lyrics data, this will return the size of the Lyrics tag or 0 if not there
    srt_size = WavpackGetTagItem (wpc, "Lyrics", NULL, 0);



    // this is rough code, remember you need to check that the malloc worked
    char *srtdata = (char*)malloc(srt_size);

    retval = WavpackGetTagItem (wpc, "Lyrics", srtdata, srt_size);
    if (retval == 0)
    {
        cout << "Error! .srt incorrectly formatted" <<  endl;
        cin >> lid;
        exit(1);
    }

    wpc = WavpackCloseFile(wpc);  // tidies up after us*/

    // Lyrics data is now is srtdata, process this as you like.....

    // don't forget to free the memory you grabbed after you've processed the SRT data


    ifstream myfile("Lyrics.srt", ifstream::in); //open lyrics !needs to be changed to read from wavpack tag marked with extention *.srt

    if (myfile.is_open())
    {
        error = 0;
        while (! myfile.eof() ) //counts the number of lyrics
        {
            error++;
            getline(myfile, line);
            lid = atoi(line.c_str()); //lyric id !Throw 'not correct format' "exception at this line x =" exit(1)
            if (lid == 0)
            {
                cout << "Error! at line " << error << ", .srt incorrectly formatted" <<  endl;
                exit(1);
            }

            while (myfile.eof() == 0 && line.length() != 0) //lyrics
            {
                getline(myfile,line);
                lyrics += line;
            }
        }
        max = lid; //last lyric ID is the max number of lyrics

        myfile.clear();
        myfile.seekg(0);

        slyrics = new lyric[max];

        for (int i=0;! myfile.eof();i++ )
        {
            getline(myfile, line);
            lid = atoi(line.c_str()); //lyric id //exception taken care of from the last while loop

            getline(myfile,line2); //<start time> --> <end time> !IF line2.size() != 29 Throw 'not correct format' "exception at this line x =" exit(1)

            lyrics.clear();
            while (myfile.eof() != 1 && line.length() != 0) //find all the lyric lines and add dynamically
            {
                getline(myfile,line); //lyrics
                lyrics += (line + '\n');
            }
            
            while (lyrics.find_last_of('\n') == (lyrics.length()-1)) //trim function
            {
                lyrics = lyrics.substr(0,lyrics.length()-1);
            }

            slyrics[i] = lyric(lid,line2.substr(0,12),line2.substr(17,29),lyrics);
        }
        myfile.close();

        ctime = 0;

        for (int i=0;i < max;++i) //print lyric objects
        {
            if (slyrics[i].stm()-ctime > 10)
            {
                wait(slyrics[i].stm()-ctime);
            }
            cout << slyrics[i].Lines() << endl;
            wait(slyrics[i].Duration() - 50);    //-50 this offset is just a guess, wait isn't accurate, well for me anyway
            system( "cls" );
            ctime = slyrics[i].ftm();
        }
    }
    else
    {
        cout << "Unable to open file";
    }

    cin >> line;

    //free(srtdata);
    
    return 0;
}

void wait ( int ms )
{
    clock_t endwait;
    endwait = clock () + ms;
    while (clock() < endwait) {}
}


currently it's clearly having problems reading the wavpack file (I've tried 2 different files, so I hope I'm right)

Code: [Select]
if (wpc == NULL) //currently always true
{
    cout << "Error! inside wavpack file" << endl;
    cin >> lid;
    exit(1);
}


directly after the lines I was having trouble with before
Code: [Select]
    open_flags = OPEN_TAGS | OPEN_2CH_MAX | OPEN_NORMALIZE;

    wpc = WavpackOpenFileInputEx (&freader, f, NULL, errorBuff, open_flags, 0);


thanks in advance RJ.

I've also been looking for foobar coding of any kind and it looks like it's on another level, I'm going to look at winamp to see if their coding is any easier to understand...

WavPack Lyrics

Reply #16
I hope to have my dev laptop back up and running this weekend, I'll try your code then.
One thing to be aware of is that in this call

Code: [Select]
wpc = WavpackOpenFileInputEx (&freader, f, NULL, errorBuff, open_flags, 0);


if it fails (which you're saying it does for you), there should be a message explaining what the problem is contained within the char buffer 'errorBuff', so you might get an idea whats going wrong by

Code: [Select]
if (!wpc) {
fputs (errorBuff, stderr);
}


but as I said, I hope (fingers crossed) to have a look at it this weekend

WavPack Lyrics

Reply #17
Code: [Select]
f = fopen("Love The Way You Lie.wv", "r");

This could be a problem. You should use an open mode of "rb" to make sure that you don't get newline translations...those will certainly corrupt the reading of a binary file and cause WavPack to error out.

WavPack Lyrics

Reply #18
sorry, I was just copying your code from before

Quote
f = fopen("somewavpackfile.wv", "r"); 
if (!f)
{
// something really bad has happened, you can't open the file, maybe time to quit
}


fixed and working
Now I've got to work out how to interpret the srtdata nicely as it is now a char* instead of a file as it was before...

WavPack Lyrics

Reply #19
Now I've got to work out how to interpret the srtdata nicely as it is now a char* instead of a file as it was before...


Ah, I should be able to help you with that in the meanwhile
Its fairly straightforward

add
Code: [Select]
#include <sstream>


and then replace your line

Code: [Select]
ifstream myfile("Lyrics.srt", ifstream::in); //open lyrics !needs to be changed to read from wavpack tag marked with extention *.srt


with

Code: [Select]
std::istringstream myfile(srtdata);


I think you'll also need to remove this line

Code: [Select]
myfile.close();


apart from that, I think the only thing you might need to change is

Code: [Select]
if (myfile.is_open())


perhaps replace with something like this?

Code: [Select]
if (srtdata)


WavPack Lyrics

Reply #20
Got it working after a few different tries. I'm impressed that something we wrote reads stuff embedded in a file, mild geek out moment when it worked. Now I guess its on to learning how winamp works... :S

WavPack Lyrics

Reply #21
Well done on getting your command line version working!

I know you said you're looking at Winamp, but I had a quick look at the foobar SDK (and did some quick googling) - certainly looks like its more than capable of doing everything you need.
For example playback_get_position() gives the current playback position within the currently played track, which you could then use to ensure you display the correct lyrics section if the user seeks within the track etc.
And its got various commands for reading information from the file etc.
So in this case you wouldn't need to include the main WavPack source code, you could use the built-in foobar tag reading code.
Anyway, just a suggestion.

 

WavPack Lyrics

Reply #22
Hi all,

just thought I'd tell you where I'm at, I had a quick look at a few different players and component code and it all looks a bit daunting, most of it point to me learning the win32 API and not many examples to base things off. I've had a lot of other uni work and things to do lately. I've set aside all of next week to drought up my thesis. And then there is only a few weeks to get it all in. So I don't know if I'll have time to code a component at this stage. I haven't yet posted anything on the winamp forums or reposted on the foobar2000 section of this forum.
I hope to have somewhere to download my sample program and a sample file so that people in those sections can take a look and perhaps give me a few suggestions. but at this stage I don't mind. Trying to code something like that with about a fortnight of actual available time left seems a little unrealistic when it's just me

Thanks again everyone who helped
RickJames

WavPack Lyrics

Reply #23
just so you guys know, I posted something in the foobar and winamp forums to no avail so far. I'm looking at taking a year off next year if all things end well this year, which they should. So I was thinking I might pick up the foobar component in my time off. I've also been looking at the interesting things Google has been doing with auto-captioning and translation tools and I think it may be possible to get some of that functionality working as well. I'm especially excited about the possibility of upload a song and it's attached lyrics to a Google Voice API and getting decent synced lyrics back, I don't know exactly how well it's going to work but some preliminary tests are promising. Even coming from an English only background I know I don't understand a lot of the singers out there, especially death metal bands and the like. So I think the idea is useful for more than just translation reasons.
Anyways I know I'm excited to start working on this but first I've got to finish off this rather hectic year.
Thanks for everyones help again and I hope to post a lot more questions in the future