Modifying MP3 file header text info - encoding

Is there a method I can use in a program to access and modify ripped music CD-MP3 file(s) header text?
There is a method available in the MusicMatch jukeboks music player, but with 2000 files ripper from 50 CD's, the job is quite formidable and the tool "supertagging' is cumbersome to use.
What I see for me is more like the visual representation of Excel, where I would have just the three fields Artist name, Song title and Album name. displayed.
The Artist field would have the option of repeating the top field down for all the song titles, Album would always be repeted for all song titles.
Song titles wil of course have to be entered for each item.
In the ripped files, every file has the fields track#, artist, album + some of less importance.
Just let me know if I am at the wrong forum for my search. I just don't know anywhere else that I might go.
For programming I might use Visual Foxpro and/or assembler. I haven't used C since early 1980's.

If you really want to develop it yourself, at least use an ID3 library, don't write the functionality yourself!
A good one is at http://id3lib.sourceforge.net/. I haven't tried it recently, but I'm sure you can call it from VFP somehow.
If you just want something that is better for tagging a shed-load of files, look at MediaMonkey.

If you want to work solely in VFP then you should use the VFP low-level utilities
FOPEN()
FCHSIZE( )
FCLOSE( )
FCREATE( )
FEOF( )
FFLUSH( )
FGETS( )
FPUTS( )
FREAD( )
FSEEK( )
FWRITE( )
These are pretty well documented within the VFP Help system and there are numerous examples on the web.
With them you can get the 'raw' data from the MP3 file, identify what you are looking for, change it, and write it back again.
The downside is that specific 'fields' (e.g. Artist name, Song title and Album name, etc.) will not be readily recognized. You would need to write code to identify these and then identify where the values reside.
Good Luck

Related

keep/copy XMP with libexif

I try to add a thumbnail to a JPEG picture using libexif.
For now I'm borrowing the code from exif (the command line tool that is shipped by the libexif team).
However I noticed the XMP tags get deleted from the metadata. There is an old bugreport here.
I tried to see how to achieve this anyway with libexif but I don't really understand how to get the XMP from input file and put it in the output file. I just want to copy all XMP data, I don't need to extract anything of it.
I saw there is a TAG EXIF_TAG_XML_PACKET in exif_tag.h but couldn't figure out how to read/write this tag.
A related solution is in this SO answer but it looks complicated. I'm not familiar coding in C.
Is it actually possible to keep all XMP when using only libexif API? Have things changed in recent years on that? How would you write this in code?
Thanks
I believe it should be somewhat straightforward. XMP fields are described in the ISO/Adobe standard. Regular Kotlin/Java/Android file I/O and some string manipulation should be all that is required.
I would start out by becoming intimately familiar with ISO 16684-1:2019. Then, write a method for your jpeg file class that grabs all the XMP fields. Store those fields in a temp file (to prevent difficult to recover data loss in the event of your code or libexif crashing). Hand the file off to libexif. Generate the thumbnail. Finally, when that's done you can restore the XMP fields. If the thumbnail is stored in an XMP field as well (and it sounds like it is), it may be easier to concatenate that field with the other ones which were already grabbed, updating the temp file so that it contains EVERY XMP field, before adding all of the XMP fields back to the jpeg.
Unfortunately, I do not currently have the time to read a 50 page ISO standard, synthesize the information, and then write the code to implement the solution. Here's a link to the standard at least, to get you started.
https://www.iso.org/obp/ui/#iso:std:iso:16684:-1:ed-2:v1:en

PDF Parsing with SWIFT

I want to parse a PDF that has no images, only text. I'm trying to find pieces of text. For example to search the string "Name:" and be able to read the characters after ":".
I'm already able to open a PDF, get the number of pages, and to loop on them. The problem is when I want to use functions like CGPDFDictionaryGetStream or CGPDFStreamCopyData, because they use pointers. I have not found much info on the internet for swift programmers.
Maybe the easiest way would be to parse all the content to an NSString. Then I could do the rest.
Here my code:
// Get existing Pdf reference
let pdf = CGPDFDocumentCreateWithURL(NSURL(fileURLWithPath: path))
let pageCount = CGPDFDocumentGetNumberOfPages(pdf);
for index in 1...pageCount {
let myPage = CGPDFDocumentGetPage(pdf, index)
//Search somehow the string "Name:" to get whats written next
}
You can use PDFKit to do this. It is part of the Quartz framework and is available on both iOS and MacOS. It is also pretty fast, I was able to search through a PDF with over 15000 characters in just 0.07s.
Here is an example:
import Quartz
let pdf = PDFDocument(url: URL(fileURLWithPath: "/Users/...some path.../test.pdf"))
guard let contents = pdf?.string else {
print("could not get string from pdf: \(String(describing: pdf))")
exit(1)
}
let footNote = contents.components(separatedBy: "FOOT NOTE: ")[1] // get all the text after the first foot note
print(footNote.components(separatedBy: "\n")[0]) // print the first line of that text
// Output: "The operating system being written in C resulted in a more portable software."
You can also still access most of (if not all of) the properties you had before. Such as pdf.pageCount for the number of pages, and pdf.page(at: <Int>) to get a specific page.
This is a pretty intensive task. There are libs like PDFKitten which are not maintained anymore. Here is a port of PDFKitten to swift that i did, with some modifications to the way the string searching / content indexing is done, as well as support for truetype fonts.
https://github.com/SimpleApp/PDFParser
[disclaimer : lib author]
[second disclaimer: this lib is 100% mit open sourced. The library has nothing to do with the company, it's not an ad or even a product, i'm posting this comment to help people, and then maybe grow a community around it, because it's a very common requirement and nothing free works well enough]
EDIT : the reason it's a pretty intensive task (not to mention all the character encoding issues), is that the PDF format doesn't have the notion of a "line of text" or even a "word". All it has is character printing instruction. Which means that if you want to find a "word", you'll have to recompute the frame of every blocks of character, using font information, and find the ones can be coalesced into a single word.
That's the reason why you won't find a lot of libraries doing those kind of features, and even some big project fail sometimes at providing correct copy/paste or text search features.

Perl: How to retrieve album metadata from MusicBrainz?

I am creating a Perl script which will move a mp3 file to my music folder in format artist/album/mp3file. Now it is possible that some of my mp3 files don't have an album tag so I thought of querying the MusicBrainz database to retrieve album metadata given track title & artist.
I am using WebService::MusicBrainz Perl module for this task, but I am not able to see any method that gives album metadata info. My current code is:
use WebService::MusicBrainz::Track;
my $ws = WebService::MusicBrainz::Track->new();
my $response = $ws->search({ ARTIST => 'Ryan Adams', TITLE => 'when the stars go blue' });
my $track = $response->track();
print $track->title(), " - ", $track->artist()->name(), "\n";
say $track->id();
So, how do I get my the album info for a given track using MusicBrainz and if it is not possible what are my alternative options?
First of all, what you want is adding metadata to mp3s which is the most common usage scenario people have. The "normal" way is to use a Musicbrainz Tagger, open these files there and work with the interface to attach the correct metadata.
The suggested (gui) tool is Musicbrain Picard
I also want to state that the Perl module is using the now deprecated Web Service Version 1 of MusicBrainz.
That Web Service has a couple of problems because it was made for another database scheme than the one used now at MusicBrainz.
However, the current Web Service Version 2 has only a python library available: python-musicbrainzngs.
You can still work with the Perl module, but if you run into "weird" problems, this might be the reason.
This is how the Web Service works in general (and how it should apply directly for the Perl module as a wrapper for this web service):
Your search gives this:
http://musicbrainz.org/ws/1/track/?artist=%22Ryan%20Adams%22&title=%22when%20the%20stars%20go%20blue%22
There you get a list of recordings of this track. These recodings occur on multiple releases (ReleaseList).
You can disregard many of these, as they are of the type "compilation". You probably want the "album" releases.
You probably ask yourself why there are multiple album releases with the same name in the list.
This is because a "release" on MusicBrainz is a combination of a release-event and a couple of mediums.
You might have an US release and a german deluxe edition and so on.
All of these releases are in one "release group".
You probably want the name of this "release group", which mostly is also the name of every release in this group.
You might want to read a bit on how the MusicBrainz Database is structured.
This is only the basic use case of course.
You might run into misspellings in artist/title, multiple or missing album release groups and other things.
However, altogether it should work and you can just drop the "problem" cases in a special directory and work with them in Picard.
Picard also has other means of identifying files per "musical analysis" (PUIDs, Acoustids)
EDIT:
my #tracklist = $response->track_list();
foreach my $track ( #tracklist ) {
print $track->title(), " - ", $track->artist()->name(), "\n";
my #releaselist = $track->release_list();
foreach my $release ( #releaselist ) {
print " ", $release->title(), " - ", $release->type();
}
}
Should work in general, but it doesn't. It gives you all tracks of the response, but somehow it can't extract releases from release_list(). Possibly because the schema changed or because the perl module is broken.
Check out our perl modules for accessing the Cover Art Archive:
http://metacpan.org/pod/Net::CoverArtArchive
More info on our archive is here, including specs:
http://coverartarchive.org/
Good luck!

Parsing HTML content to use with iPhone app

I don't even know if the title for this question is appropriate, since I'm really lost and need some advice, a starting point to what I need to accomplish.
My iPhone app plays audio streamed from the Internet, with my custom made player. Some links are live streams from Akamai and others are audio files stored on a website. I'm OK with the live streams, but my problem is with the audio files.
As I have many stored audio files that the user can choose from, in different languages, and I don't want to hardcode all of them on my application.Then I need a clever way for the user to browse on the app (pushing the information from the Internet) until he reaches the desired file to play.
The website is organized like this:
First there is list, having all available programs. The user chooses the desired program, then another page shows up and he has to choose a day of the week to play.
My question is: how can I parse this content, with programs and days of the week to choose from? Should I look into HTML parsing? Is there a better/simpler way, like making XML files on the website?
If this helps, the all the webpages end with the .aspx extension.
Please, any advise from a more experienced programmer will greatly help me. Thank you!
I don't think parsing HTML would be the best implementation here. Go for a structured source that doesn't have viewable markup to worry about parsing out or ignoring altogether (also will mean fewer resources thrown at parsing the markup because you will only be parsing what matters).
I'd suggest consuming an XML or JSON source that can be converted to a NSDictionary or other data structure for app use. Here's a neat little class that converts an XML source to an NSDictionary: http://troybrant.net/blog/2010/09/simple-xml-to-nsdictionary-converter/
TBXML is another light-weight XML parser for Objective-C that makes implementing a custom data object up to you: http://www.tbxml.co.uk/
If you'd rather use JSON, there are a number of helpers out there. A good place to start looking would be here: http://cocoaobjects.com/?s=json
If I have understood your question correctly, whatever source you choose, you're likely to want to wind up with a dictionary object that looks something like this:
programs = (
{
program_name: "Foo";
tracks = (
{ day: Monday;
track: audio_file1.mp3;
},
{ day: Tuesday;
track: audio_file2.mp3;
},
{ day: Wednesday;
track: audio_file3.mp3;
}
);
},
{
program_name: "Bar";
tracks = (
{ day: Monday;
track: audio_file4.mp3;
},
{ day: Tuesday;
track: audio_file5.mp3;
},
{ day: Wednesday;
track: audio_file6.mp3;
}
);
},
{
program_name: "Baz";
tracks = (
{ day: Monday;
track: audio_file7.mp3;
},
{ day: Tuesday;
track: audio_file8.mp3;
},
{ day: Wednesday;
track: audio_file9.mp3;
}
);
};
);
Once you've worked out your data source, and converted it to a native data object for working with in Obj-C, you should be able to proceed with coding up a UI that can iterate through the dictionary to provide a list of programs and, in turn, a list of days for each program with accompanying audio files to select to play.
I had a similar need. Consuming data from an ASP.NET site. In the end I used JSON from the .NET side and return JSON. Then, I used the json-framework from Google Code to convert the JSON returned to an NSDictionary. From there the rest is history.
If you are using .NET MVC, then returning JSON results is super simple in a controller. Since you have aspx extensions, I assume that is not the case. There are tons of JSON parsers for C# listed at the bottom of the json.org homepage.
if the website content is static, I would hard code the file names and appropriate URL's to your server within the app and let the user scroll through the list of available items.
if the website content changes, then I would create an XML file on a server which your app downloads on launch (or as you deem fit) and parse within the app, then continue as per static content.
hope this starts you off in the right direction.
Think outside the box: use UIWebView
How about instead of thinking how to parse data and then write UI code to display it we think more of the big picture: we want to present to iPhone user sequence of screens to select and play a recording, and this should be coming from a web server. Only if there was such a tool... but wait, there is! It's called web browser and in the form of UIWebView you can integrate it in your interface, with a little twist.
First, adding UIWebView is very easy, check this http://zpasternack.blogspot.com/2010/09/stupid-uialertview-tricks-part-i.html for illustration.
So let's say we added web view and user can select an audio file from there, what happens then? Turns out you can tell it what should happen, check this question UIWebView open links in Safari . You can hook your code into handling of link clicks and do whatever you please (like hide web view and show player etc).
To give an example, say first in the web view you load
http://foobar.com/somepath/listOfPrograms
which happens to be web page showing list of the programs (which thanks on some clever CSS could look just like an UITableView if you please). User clicks on a programing name, that goes to
http://foobar.com/somepath/programs/CarTalk
which page presents list of weekly shows (again iPhonesque formatted) and when clicked on a link, this now points to
http://audio.foobar.com/somesuch/45678913.mp3
at which point your code recognizes that's audio URL, apprehends control and plays it however it pleases.
How useful is that you may wonder. The answer is "very" :-). It moves the presentation structure away from the app - and to the web server. The app's entry into the UIWebView is the initial URL and the exit is click on audio file link. In a few months someone decides they want the choices not to be made fist programming name and then day of the week; or add additional layer of choice by language or country. No problemo, no need to release new version of the app, just tweak a bit the web pages on the server and the app will pick it up automagically.
It also makes testing the web server side easy - just point any browser to the initial page URL and click-through to see if you make it to a viable audio file. The web master can handle that independently of you, the app writer. You don't even have to care what they use on their side to get those pages, is it hard-coded in html, or comes from a SQL DB, XML tarpit, whatever.
If it were me, and assuming I have some clue as to what you're talking about, I would have a database that shows the relationship between the audio content and the date. Then your spinner for the content would just be updated by a query...
So, for instance, assume a table
+----------------------------------------------------------------------+
| Filename | Language | Date |
+----------------------------------------------------------------------+
| kjslfiewofksalfjslfakj | Swahili | 2011-11-01 |
| shfaahflajfewifhlanfww | Guyanese | 2011-10-08 |
| weijalfjlajfljalsfjewn | French | 2011-11-01 |
| fiwojancanlsjfhkwehwlk | Swahili | 2011-11-01 |
| fhalksflwiehlfnaksflhw | Swahili | 2011-11-03 |
+----------------------------------------------------------------------+
Okay, so if joe schmo reaches the page for the show dated 2011-11-01 and his language is Swahili, two rows will be returned:
+----------------------------------------------------------------------+
| Filename | Language | Date |
+----------------------------------------------------------------------+
| kjslfiewofksalfjslfakj | Swahili | 2011-11-01 |
| fiwojancanlsjfhkwehwlk | Swahili | 2011-11-01 |
+----------------------------------------------------------------------+
You could also easily add references for the date and language that indicate an Akamai record. It doesn't strike me as terribly complicated, but it may mean significant redesign for you. However, you've been purposefully vague on details, so hopefully at least this points you in a right direction.
Edit:
Alright, so after re-reading, there may be a relatively easy way to control content in its organization by using directory structures, but it takes a backseat to my proposed table.
As I understand it, there are potentially three categories at work: program, date, and language.
If I create a file structure (assuming root):
/public_html/audio/[date]/[language]/[program_name].mp4
Then, when the user selects a date and language, we might have:
/public_html/audio/2011-11-14/swahili/the_linux_show.mp4
Then, all we'd have to do is have the $_POST data from the selectors read to provide the show... Unfortunately, this will mean that we have to know the date that the show aired, then language, then show name. This would be a far worse way than a database, but could be done. Use ASP to read directory contents and you can list using loops. Seems pretty simple, but not at all elegant.

How do I use IPTC/EXIF metadata to categorise photos?

Many photo viewing and editing applications allow you to examine and change EXIF and IPTC data in JPEG and other image files. For example, I can see things like shutter speed, aperture and orientation in the picture files that come off my Canon A430. There are many, many name/value pairs in all this metadata. But...
What do I do if I want to store some data that doesn't have a build-in field name. Let's say I'm photographing an athletics competition and I want to tag every photo with the competitor's bib number. Can I create a "bib_number" field and assign it a values of "0001", "5478", "8124" etc, and then search for all photos with bib_number="5478"?
I've spent a few hours searching and the best I can come up with is to put this custom information in the "keywords" field but this isn't quite what I'm after. With this socution I'd have to craft a query like "keywords contains bib_number_5478" whereas what I want it "bib_number is 5478".
So do the EXIF and/or IPTC standards allow addtional user-defined field names?
Thanks
Kev
It can be used for that, but it really shouldn't: it's meant to be user-editable and so isn't a safe place to put critical metadata. Using an XMP sidecar is better for this kind of thing: in XMP, any field added that a given app does not understand is, according to the standard, supposed to be ignored by that app and not destroyed.
I don't know if there are applications to do this but by the standards described for JPEG files there is a field called Comments where you can assign values that could act like tags.
C# code:
using System.Windows.Media.Imaging;
using System.IO;
...
FileStream fs = new FileStream(#"<img_path>", FileMode.Open, FileAccess.ReadWrite);
BitmapMetadata bmd = (BitmapMetadata)BitmapFrame.Create(fs).Metadata;
bmd.Comment = "Some Comment Here";
also if you are looking for an application that already has this functionality built into it, then might i recommend Irfan View (open pic, go to Image menu, click on Comments button).
Hope this helps.