HowTo: Generate Pretty, Curated MAME Playlists the Easy(ish) Way

RetroArch playlists let you find your content quickly without snooping through folders. But it’s difficult to generate playlists when RetroArch doesn’t supply a content database (.rdb) file for a given library. That’s exactly the case with MAME and its massive 36,000+ file arcade romset.

This guide, utilizing RomLister and two modified AHK scripts, will help you whittle down MAME’s romset, split it into genres, get the appropriate ROMs copied into genre subfolders, and automatically generate playlist files that have human-readable game titles and two types of pretty thumbnail images. It’ll make everything look great in RetroArch and also save disk space, by only copying files you need.

Here’s a video showing the playlists in action:

While the results are good and the process as streamlined as currently possible (?), it will still take some real time if you want to get your hands dirty and divvy up MAME’s 100+ genres into your own custom-sorted playlists (Step 2, below). If that’s too much hassle, see if you like the ready-made genre groupings I came up with and just implement those, via either the supplied RomLister search strings or, even faster, the optional, pre-compiled batch files linked in Step 1. Either way, you’ll end up with nicely curated, per-genre MAME playlists.

In addition to RetroArch, you’ll need:

[ol] [li]AutoHotkey (Windows app)[/li][ul] [li]Two AHK scripts from this guide (modified from Tatsuya79’s originals) [/li][/ul]

[li]RomLister (Windows app, not needed if you decide to use the pre-compiled batch files)[/li][ul] [li]latest MAME .exe [/li][li]Controls.xml (alt link if previous down) [/li][li]Catver.ini (grab the English version) [/li][li]nplayers.ini (optional) [/li][/ul]

[li]Text editor with good find/replace, like Notepad++ (Windows app) [/li][li]Image editor (optional) [/li][li]MAME romset of an appropriate version, zipped and split (not merged). The current 0.176 zipped split set is 56.3GB. [/li][li]MAME Snap and/or Title images (I suggest both; download the base .170 packs and all the updates for each) [/li][/ol] (Note: While this guide relies on two key pieces of Windows software, the underlying principles for putting together and enhancing RetroArch playlists apply cross-platform, and there’s a good chance Linux users could get the RomLister and AutoHotKey stuff done in WINE. Hence posting in the General forum.) History

[ul] [li]10/24/2016 - Created 31 new MAME icons. Added pre-compiled batch files pack (see Step 1) for saving mucho time. Refined various searches and main exclusion string (@X) for more accurate results. Updated Final Search Queries doc. Added read-only toggle feature to AHK #2. Updated ~~~TidyUp.bat with new clones and a simple BIOS copying feature (see full contents on Pastebin or in the pre-compiled batch pack). Nips and tucks throughout body text. [/li][li]08/16/2016 - Created ~15 new MAME icons. [/li][li]08/14/2016 - Created ~75 new MAME icons. [/li][li]08/11/2016 - Initial post. [/li][/ul]

[HR][/HR]Step 1: Download and Organize

For the purposes of this guide I’m going to suggest a specific folder setup. You can freestyle if you understand what that’ll affect.

[TABLE=“width: 900, align: center”]

Put your split MAME romset wherever you store such things.

Create four subdirectories: ~Snaps ~SnapsFriendly ~Titles ~TitlesFriendly

(I like tildes because they pop to the top in Explorer’s alphabetical order.)

Extract the MAME Snap images to ~Snaps and the MAME Title images to ~Titles. Now we have all the necessary files in place. [TABLE=“width: 475, align: center”] [TR] [TD]

[/TABLE] [/TD] [/TR]

[TABLE=“width: 460, align: center”] [TR] [TD]

[/TABLE] [/TD] Now you have a choice.

You can either continue on to Steps 2 and 3, using RomLister to pare down your romset into custom genres of your own preference (satisfying, but takes a while), or just go with the genre sortings I came up with and skip to Step 4. To do so you’ll need…

>>> [U]Link to Download: Pre-compiled MAME Genre Batch Files[/U] <<<

The batch files in this pack will copy your ROMs into the correct genre folders so you can proceed directly to Step 4, in which you’ll feed the sorted ROMs into two AutoHotKey scripts to generate thumbnail images and playlist files.

If you’re gonna warp to 4 be sure to check the readme in the zip for instructions on how to use the pack’s contents. Also beware of Lakitu. [/TR] [/TABLE]

[HR][/HR] Step 2: Filter your Romset

Buckle up, this can be a timesink. Those 36,000 ROM files? We need to sift through that jungle and pull out only the ones you’re interested in playlisting.

Thankfully, RomLister makes this otherwise overwhelming task manageable. Learning a few tricks will unlock its power.

Upon first run it’ll ask for four files, the ones linked right below the video. Supply them and it’ll crunch for awhile, smushing the four files together into a RLMasterDB.xml file. This huge text file (mine’s 193MB) contains a mountain of information about your MAME romset: full game names, hardware details, how many buttons each game uses, detailed game genres, etc.

RomLister lets us run searches against all that data, showing us which ROMs our search queries apply to. It can turn that output into Windows batch (.bat) files (Step 3) which copy the singled-out ROMs wherever we like… such as folders split by genre. A-ha.

[TABLE=“width: 900, align: center”]

This is RomLister

Specifically, its main interface.

Click the “List all ROMs” button to make sure your database created OK. It should come up with a huge list of 30000+ ROMs.

This results window is the “working list.” You can remove individual results (right click), run a new search to add additional results to the working list, or, if you’re satisfied with it, export the list to a variety of formats.

Back to the interface. All the checkboxes correspond to information in the database we just compiled. Clicking the boxes changes the search query in the bottom “-find” field.

Searches setup with the GUI are coarse and unrefined. The XML database contains subgenres like Fighter / Versus and Fighter / 2.5D, but the GUI only lets us search for the parent genre, Fighter. How can one separate beat 'em ups and versus fighters, since they were all lumped under “Fighter”?

The answer is to ignore the GUI entirely by writing your own custom search strings. Let’s learn how.

The contents of the -find field determine what you search for, and you can modify the query by typing down there.

Once you learn the syntax you can run super-powerful searches that find exactly what you’re looking for. Be careful, though, because the next time you click a checkbox it’ll reset the query to reflect only the state of the GUI, erasing your modifications. [TABLE=“width: 560, align: center”] [TR] [TD]

[/TABLE] [/TD] [/TR] [/TABLE]

[TABLE=“width: 900, align: center”]

Search Basics

Right-click a search result and choose View Details to see all the info the database has for that ROM. It’s quite a lot, and we can use any bits we want to narrow down searches.

For example, searching ‘<nplayers>1P’ (see it in the screenshot?) would pull up all other ROM records that have that text. Congrats! You just found all the single-player games, at least so far as our database is accurate (it’s great on genres, but has gaps elsewhere).

RomLister syntax is simple, and while I’ll try to cover the important stuff, you really want to check out the wiki’s brief tutorials to get the real lowdown.

Basic Operators

[TABLE=“class: outer_border, width: 350, align: center”] [TR] & | ! ( ) ’ ’ @[macro] [TD=“align: center”] Ampersand is AND Pipe character is OR Exclamation is NOT Parentheses denote grouped items Single quotes search for exact text At sign inserts the named macro

[/TABLE]

Speaking of macros, in the RL folder open rlmacros.txt and paste this new line: @X = (!cloneof & !emulation=preliminary) & !(isbios=yes) & !(’ Mature’ | PlayChoice | ‘Mega Play’ | ‘Nintendo Super System’ | ‘SNES bootleg’ | Megadrive | huc6260 | (n2a03 & Vs.)) This will soon save us a lot of typing.[/TD] [TABLE=“width: 409, align: center”]

[TD]

[/TABLE] [/TD] [/TR] [/TABLE]

[TABLE=“width: 900, align: center”]

Begin the Purge

[TABLE=“width: 888, align: center”] [TR] [TD]Time to search and destroy. 36,000 ROMs… let’s cut that down, a lot.

Clear the search box and paste (!cloneof & !emulation=preliminary). This is the standard string to eliminate all clones and games that don’t yet work. Hit enter, and your computer will think a bit.

Ah, that brings us down to 5,040 or so original games that work (your numbers will vary a bit). Much better, but we’re just getting started.

I notice some other things I don’t want in there: BIOS files, strip poker sims, and games sourced from 8- and 16-bit consoles, like PlayChoice 10 and MD/SNES bootlegs. New query: (!cloneof & !emulation=preliminary) & !(isbios=yes) & !(’ Mature’ | PlayChoice | ‘Mega Play’ | ‘Nintendo Super System’ | ‘SNES bootleg’ | Megadrive | huc6260 | (n2a03 & Vs.)) Say, does our search string look familiar? It does! It’s that line you pasted into rlmacros.txt. Since it’s a macro, you can invoke it by its name, @X. Searching for @X should give the same result as typing that long exclusion string. From now on, just add @X to the end of each search string to filter out clones, games that don’t work, and other stuff we don’t want. Convenient!

If you run that long exclusion string you’ll notice we’re down to 4,508 ROMs, give or take. How to eliminate even more? We’ll start slicing and dicing the romset into more manageable chunks. [TABLE=“class: outer_border, width: 300, align: center”] [TR] [TD]Why did that last search work?

Lemme explain those last two bits.

huc6260 is the GPU of the PC-Engine / TurboGrafx-16, and I noticed that the Turbo games I wanted to remove had that in their details. So by searching for “NOT huc6260” ( !huc6260 ) we can eliminate all those games.

As for (n2a03 & Vs.) , n2a03 is a CPU used by Nintendo’s NES-based arcade efforts, including the Versus system. However, searching just !n2a03 eliminated a few non-Nintendo games that also used that CPU, so I made the search more specific by also requiring “Vs.”, which was in every Nintendo Vs. game’s title. This combination of CPU and title string finds exactly the games I want.

[/TABLE] [/TD] [/TR] [/TABLE] [TABLE=“width: 800, align: center”]

To do that (and start organizing in earnest) we turn to the genres RomLister imported from catver.ini.

Catver.ini gave RomLister 17 top-level genres: [TABLE=“class: outer_border, width: 500”] [TR] [TD]Ball & Paddle Casino Fighter Pinball Quiz Sports

Casino Climbing Maze Platform Rhythm Tabletop

Climbing Driving Multiplay Puzzle Shooter

[/TABLE] [/TD] [/TR] [/TABLE] Most have more specific subgenres under them. All told, there are 164 or so genre classifications, with 30 just being “mature” variants of categories like Shooter / Flying Vertical.

Let’s start by removing some obvious ones (feel free to remove more or re-add whatever you like). For my tastes I lopped off Casino, Quiz, Rhythm, Tabletop, and mature variants. Now we’re down to 106:

[TABLE=“width: 888, align: center”]

Ball & Paddle Ball & Paddle / Breakout Ball & Paddle / Pong

Climbing

Driving Driving / 1st Person Driving / Boat Driving / Plane Driving / Race Driving / Race (chase view) Driving / Race (chase view) Bike Driving / Race 1st P Bike Driving / Race 1st Person Driving / Race Bike Driving / Race Track

Fighter / 2.5D Fighter / 2D Fighter / 3D Fighter / Field Fighter / Misc. Fighter / Multiplay Fighter / Versus Fighter / Versus Co-op Fighter / Vertical

Maze Maze / Digging Maze / Driving Maze / Fighter Maze / Outline Maze / Shooter Large Maze / Shooter Small Maze / Surround

Multiplay Multiplay / Compilation Multiplay / Mini-Games

Pinball Pinball / Pachinko

Platform / Fighter Platform / Fighter Scrolling Platform / Run Jump Platform / Run Jump Scrolling Platform / Shooter Platform / Shooter Scrolling

Puzzle / Cards Puzzle / Drop Puzzle / Match Puzzle / Maze Puzzle / Misc. Puzzle / Outline Puzzle / Sliding Puzzle / Toss

Shooter / 1st Person Shooter / 3rd Person Shooter / Command Shooter / Driving Shooter / Driving (chase view) Shooter / Driving 1st Person Shooter / Driving Diagonal Shooter / Driving Horizontal Shooter / Driving Vertical Shooter / Field Shooter / Flying Shooter / Flying (chase view) Shooter / Flying 1st Person Shooter / Flying Diagonal Shooter / Flying Horizontal Shooter / Flying Vertical Shooter / Gallery Shooter / Gun Shooter / Misc. Shooter / Misc. Horizontal Shooter / Misc. Vertical Shooter / Versus Shooter / Walking

Sports / Armwrestling Sports / Baseball Sports / Basketball Sports / Bowling Sports / Boxing Sports / Bull Fighting Sports / Darts Sports / Dodgeball Sports / Fishing Sports / Football Sports / Golf Sports / Handball Sports / Hang Gliding Sports / Hockey Sports / Horse Racing Sports / Horseshoes Sports / Misc. Sports / Multiplay Sports / Ping Pong Sports / Pool Sports / Rugby Football Sports / Shuffleboard Sports / Skateboarding Sports / Skiing Sports / SkyDiving Sports / Soccer Sports / Sumo Sports / Swimming Sports / Tennis Sports / Track & Field Sports / Volleyball Sports / Wrestling

[/TABLE] [TABLE=“width: 888, align: center”]

Some top-level genres have standalone categories, like Driving and Maze, while categories like Puzzle and Sports do not. Don’t forget some games exist only in those top-level genres.

Right off the bat I know I don’t care about separating Sports games into subgenre playlists like Baseball, so for my purposes those 32 genres became one playlist comprising a healthy 399 ROMs (search: ‘<category>Sports’ @X ). 75 genres left to sort.

After looking at the various games in Driving, I decided the same thing there. ‘<category>Driving’ @X brings up 172 ROMs, a pretty optimally sized playlist.

With Sports and Driving flattened we’re down to 65 genres. Those might only take like… a day to organize! (Okay, more like two…) three… [TABLE=“class: outer_border, width: 490, align: center”] [TR] [TD]HAY I maed u sum mMakROS

Games that require CHDs: @C = (cdrom | harddisk | laserdisc) & !(isbios=yes) !(’<category>Business Computer’ | ‘<category>Home Computer’ | ‘<category>Development Computer’ | ‘<category>Single Board Computer’ | ‘<category>Laptop’ | ‘<category>Game Console’ | ‘<category>Utilities’ | ‘huc6260’ | ‘Xerox’)

Games that support sound samples: @S = (‘sample name’)

BIOS files (it’s handy to give these their own folder for easy grabbin’): @B = B [/B] Nintendo Vs. games: @V = (n2a03 & Vs.)

[/TABLE] [/TD] [/TR] [/TABLE] [/TD] [/TR] [/TABLE] [TABLE=“width: 900, align: center”]

Divide and Conquer

Faced with all these genres, some of them hard to understand (Fighter / Field? Maze / Shooter Large? Fighter / Versus Co-op? WTF?) I began running searches on every last one to see what games went where. I took notes on key titles that belonged to each genre, which helped me remember what the genres meant and shuffle all these categories around later when it was time to divvy them up into my custom genre playlists.

We’ll go through my process to assemble the genre playlists so you can see how it’s done. Then you can either use/modify my groupings or make your own.

[TABLE=“width: 888, align: center”] [TR] [TD]Looking at everything, I came up with 15 RetroArch playlists I could cobble together from the 65 remaining genres: [TABLE=“class: outer_border, width: 700, align: center”] [TR] [TD]Action Beat 'Em Up Driving Fighting Lightgun Maze Misc. Platform Platform Single Screen Puzzle Shooting Hori Shooting Misc. Shooting Single Screen Shooting Vert Sports

[/TABLE] [/TD] [/TR] [/TABLE] Some of the playlists required no assembly at all.

I wanted side-scrolling Beat 'Em Ups (Double Dragon, Final Fight) to be their own playlist, and luckily, catver.ini puts the vast majority of them under Fighter / 2.5D: ‘<category>Fighter / 2.5D’ @X (96 games). That was easy! Along with Sports (399 games) and Driving (172 games), that’s three playlists dealt with.

Fighting games (SF2, MK) were conveniently under Fighter / Versus. Search for ‘<category>Fighter / Versus’ @X, right? Almost! I eventually noticed redundant JAMMA PCB versions of SNK vs. Capcom and KoF 2003 as well as a Fighter subgenre that I wanted to put in another playlist. This eliminated them: ‘<category>Fighter / Versus’ & !(‘Fighter / Versus Co-op’ | ‘JAMMA PCB’) @X (195).

Lightgun games (I know they’re not all “lightguns,” I just like the term) was a cinch with ‘<category>Shooter / Gun’ @X (74).

Five playlists sorted. I grayed them out above. Now the trickiness will slowly ramp up.

Puzzle wasn’t too bad; I thought the Puzzle / Match genre looked pretty boring so I excluded it: ‘<category>Puzzle’ & !(‘Puzzle / Match’) @X (183).

My playlist idea Platform Single Screen (single-screen platformers) matched up perfectly with catver.ini’s Platform / Run Jump (Bubble Bobble, DK), but I didn’t want Platform / Run Jump Scrolling (Alex Kidd, Bonk, Sonic) to get sucked in too; that would better live under plain old Platform. So: ‘<category>Platform / Run Jump’ & !(’<category>Platform / Run Jump Scrolling’) @X (118).

[TABLE=“width: 888, align: center”]

Platform (scrollers like Mario and Sonic) got complicated. It was easy to remove the single-screen games, but I thought the very small nine-game subgenre Platform / Fighter (Rampage, The Outfoxies) was better placed under a catch-all Action playlist.

Further, I saw some games that, to me, just did not qualify as platformers. Platform / Fighter Scrolling had games like Black Tiger and Cadash but also Altered Beast, Bad Dudes, and Vigilante. I earmarked the latter for Action (you might prefer Beat 'Em Up). Similarly, Platform / Shooter Scrolling had Alien Storm. Wut? That’s a Beat 'Em Up! Hence the second half of this final query for Platform: (’<category>Platform / Fighter Scrolling’ | ‘<category>Platform / Shooter’ | ‘<category>Platform / Run Jump Scrolling’) @X !(altbeast | baddudes | vigilant | astorm | cbuster | narc | aladmdb | evilston | ‘JAMMA PCB’) (160).

Keep notes on any miscategorized games you filter out. We’ll take care of them all later. [TABLE=“class: outer_border, width: 360, align: center”] [TR] [TD]Platformers are Hateful

Platformers have been annoying to nail down. I kinda wanted a run ‘n’ gun playlist for Contra-likes but ‘<category>Platform / Shooter Scrolling’ @X (65) was too broad, with games like Magician Lord, Narc, Son Son, and Wonder Boy. Kind of a catch-all mess IMO.

I also considered combining Contra-likes with ‘<category>Shooter / Walking’ @X (49, Commando, Ikari Warriors, Mercs, Valkyrie no Densetsu) but then that would gut Action of almost a third of its 160 games.

[/TABLE] [/TD] [/TR] [/TABLE] Catver.ini has no less than 23 types of Shooters. Lightgun subtracted one. Three of the playlists proved simple enough: Shooting Hori: (’<category>Shooter / Flying Horizontal’ | ‘<category>Shooter / Driving Horizontal’ | ‘<category>Shooter / Misc. Horizontal’) @X (132) Shooting Vert: (’<category>Shooter / Flying Vertical’ | ‘<category>Shooter / Driving Vertical’ | ‘<category>Shooter / Misc. Vertical’) @X (272) Shooting Single Screen: (’<category>Shooter / Gallery’ | ‘<category>Shooter / Field’ | ‘<category>Shooter / Versus’ | ‘<category>Shooter / Command’) @X (237)[TABLE=“width: 888, align: center”]

Every remaining Shooter subgenre (including games like Afterburner, Battle Zone, Cabal, Metal Hawk, Star Wars, Viewpoint) but one became Shooting Misc. The holdout was Shooter / Walking, the home of Commando, Out Zone, and Shock Troopers, which migrated to Action. Here’s the bear of a query that made Shooting Misc. (163):

(’<category>Shooter / 1st Person’ | ‘<category>Shooter / 3rd Person’ | ‘<category>Shooter / Flying 1st Person’ | ‘<category>Shooter / Flying (chase view)’ | ‘<category>Shooter / Flying Diagonal’ | ‘<category>Shooter / Driving 1st Person’ | ‘<category>Shooter / Driving (chase view)’ | ‘<category>Shooter / Driving Diagonal’ | ‘<category>Shooter / Misc.’ | ‘<category>Shooter / Flying’ | ‘<category>Shooter / Driving’) & !(‘Shooter / Misc. H’ | ‘Shooter / Misc. V’ | ‘<category>Shooter / Flying H’ | ‘<category>Shooter / Flying V’ | ‘<category>Shooter / Driving V’ | ‘<category>Shooter / Driving H’) @X & !(Pang | Stargate | Salamander | ‘Section Z’)

(I felt those last three games would better fit in Shooting Hori. Defender was already there…) [TABLE=“class: outer_border, width: 350, align: center”] [TR] [TD]Take it Slow… j/k don’t

That query over there is a handful. If it gets to be too much, remember you can also break it into smaller searches and run them one after the other:

‘<category>Shooter / 1st Person’ @X ‘<category>Shooter / 3rd Person’ @X ‘<category>Shooter / Flying 1st Person’ @X

As long as you don’t close the working list your new results will keep adding to it. Then again, one bad search with unexpected results could fill it with junk, forcing you to start over. The all-in-one, long query method is much faster, too.

[/TABLE] [/TD] [/TR] [/TABLE] You get the idea: Use specific searches to slice up your romset into manageable chunks that will make good playlists. Keep notes on errata you will fix later.

To find further examples, including every single search I ended up using to implement my playlists, check out my notes in this doc:

>>> Link to Document: Final Search Queries, Genre Notes, and Misc. Tidbits <<<

I’ll wait here.

Got your taxonomy all figured out yet? No? Keep at it, it’s an arduous process. Or if my setup doesn’t give you conniptions (“Vigilante… UNDER ACTION???”) feel free to just use mine, either via the searches in the linked document – having all the catver.ini genre searches already figured out will save you time – or the pre-compiled batch files pack linked in Step 1.[/TD] [/TR] [/TABLE]

[HR][/HR]Step 3: Let’s Make Batch Files

All done? Nice! Curating that hot mess of ROMs was by far the hardest part of the process (but think how much harder it would have been without RomLister!).

The rest is a mostly automated breeze. RetroArch playlists, here we come. [TABLE=“width: 900, align: center”]

[TABLE=“width: 888, align: center”] [TR] [TD]Once you’ve got your ROM lists all curated it’s finally time to do something with them: We’re gonna turn each of those final playlist queries into batch files that will copy the appropriate ROMs to the appropriate subfolders.

As you’ll recall I had 15 playlists, so I made 15 folders. (Secret: I also made “special collection” playlists for Neo Geo, Nintendo Vs., and Vector games. The relevant searches are in the linked document.) Something like this image is what you’re aimin’ for:

Now run one of your final playlist searches. I’ll do Fighting: ‘<category>Fighter / Versus’ & !(‘Fighter / Versus Co-op’ | ‘JAMMA PCB’) @X [TABLE=“width: 716”] [TR] [TD]There’s a drop-down at the bottom of the working list window. Choose Batch File and click Preview List. You’ll see a sample preview line: copy %ROM%.zip c:\mame\roms

Change the destination path to the place you want the playlist’s ROMs to end up. (Remember that double quotes must surround paths that have spaces. I include them all the time, just to not worry about it.) While you can use a full path… copy %ROM%.zip “C:\MAME Roms\Fighting”

…I like to use shorter relative paths. In this case, quotes optional: copy %ROM%.zip “.\Fighting” [TABLE=“width: 240, align: center”] [TR] [TD]

[/TABLE] [/TD] [/TR] [/TABLE] [/TD] [TABLE=“width: 155”]

[TD]

[/TABLE] [/TD] [/TR] [/TABLE] [TABLE=“width: 888, align: center”]

A preview list will appear. Look good? Click Save and save it in your main ROMs folder with a tilde or two at the start and a .bat extension. For example, ~~Fighting.bat. This way it will bubble to the top of your massive folder of ROMs.

Now do the same for each intended playlist: Run the search, save the batch file. You’ll end up with one batch file for each playlist/folder.

You’re ready to let 'er rip! Run each .bat file and it should copy all the specified ROMs to the relevant subfolder. All those previously empty folders will now contain your carefully curated games. [TABLE=“class: outer_border, width: 400, align: center”] [TR] [TD]Super Elite Deluxe Batch File Trick

If you append two pipe characters and “PAUSE” to the end of each line of your .bat files the script will pause during execution if it can’t find one of the ROMs it’s supposed to copy. It’s a useful way to see if you’re missing anything.

Just use your text editor to do a find/replace on the destination path:".\Fighting" becomes “.\Fighting” || PAUSE

[/TABLE] [/TD] [/TR] [/TABLE] Step 3 concludes with a little housecleaning. Use your text editor to create an empty batch file and paste in a line from one of the batch files RomLister created. Now we’ll edit this new file (I called mine ~~~TidyUp.bat) to copy any ROMs you pulled aside earlier to their proper homes. (You did keep notes, right?)

[TABLE=“width: 888, align: center”]

You can see how mine starts over to the right. Those are mostly games I filtered out earlier and earmarked to go elsewhere.

There is also the issue of worthwhile clones: A few are worth keeping, or even replacing their parent games with.

For example, the parent Simpsons and TMNT ROMs (simpsons.zip, tmnt.zip) are four-player cabs, and tie each character to a certain player slot. There are two-player versions of each (simpsons2p.zip, tmnt2po.zip) that allow players to choose any character. Another neat one is Bubble Bobble: Lost Cave (bublcave.zip) a 2012 hack that translates the levels from various console ports into the arcade version of Bubble Bobble (bublbobl.zip).

UltraMegaHyperNewbie at the HyperSpin forums is keeping track of notable clones, so check out their list and add any that sound interesting to your batch file.

copy altbeast.zip ".\Action" || PAUSE REM Altered Beast
copy baddudes.zip ".\Action" || PAUSE REM Bad Dudes
copy cbuster.zip ".\Action" || PAUSE REM Crude Buster
copy evilston.zip ".\Action" || PAUSE REM Evil Stone
copy narc.zip ".\Action" || PAUSE REM NARC
copy vigilant.zip ".\Action" || PAUSE REM Vigilante
copy astorm.zip ".\BeatEmUp" || PAUSE REM Alien Storm
copy wonder3.zip ".\Misc" || PAUSE REM Three Wonders
copy ladygolfe.zip ".\NintendoVs" || PAUSE REM Golf Women Ver.
copy salamand.zip ".\STGHori" || PAUSE REM Salamander
copy sectionz.zip ".\STGHori" || PAUSE REM Section Z
copy sexyparo.zip ".\STGHori" || PAUSE REM Sexy Parodius
copy stargate.zip ".\STGHori" || PAUSE REM Stargate
copy pang.zip ".\STGSingle" || PAUSE REM Pang
copy spang.zip ".\STGSingle" || PAUSE REM Super Pang
copy pang3.zip ".\STGSingle" || PAUSE REM Pang 3
copy mpang.zip ".\STGSingle" || PAUSE REM Mighty! Pang

[/TABLE] Here’s my clone section:

copy aligatorun.zip ".\STGMisc" || PAUSE REM Alligator Hunt unprotected (reg. ver. is marked preliminary)
copy drgninja.zip ".\Action" || PAUSE REM Bad Dudes vs. Dragon Ninja
copy bublcave.zip ".\PlatformSingle" || PAUSE REM Bubble Bobble Lost Cave hack
copy sboblbobla.zip ".\PlatformSingle" || PAUSE REM Super Bubble Bobble hack
copy dkongx11.zip ".\PlatformSingle" || PAUSE REM Donkey Kong II hack
copy gaunt22p.zip ".\Action" || PAUSE REM Gauntlet II 2-player
copy gauntlet2p.zip ".\Action" || PAUSE REM Gauntlet 2-player
copy hcastlek.zip ".\Platform" || PAUSE REM Haunted Castle JPN (less brutal)
copy ikarijpb.zip ".\Action" || PAUSE REM Ikari Warriors joystick hack
copy jojon.zip ".\Fighting" || PAUSE REM JoJo's Venture No CD
copy jojobane.zip ".\Fighting" || PAUSE REM JoJo's Bizarre Adventure No CD
copy kchampvs2.zip ".\Fighting" || PAUSE REM Karate Champ 2-player
copy kf2k5uni.zip ".\Fighting" || PAUSE REM King of Fighters 2005 Anniv (hack of 2002)
copy lifefrce.zip ".\STGHori" || PAUSE REM Life Force (enhanced Salamander)
copy mhavocrv.zip ".\STGMisc" || PAUSE REM Major Havoc hack "Return to Vax"
copy mshvsfj.zip ".\Fighting" || PAUSE REM Marvel Super Heroes vs. Street Fighter JPN
copy metamrphj.zip ".\BeatEmUp" || PAUSE REM Metamorphic Force JPN more fair, has lifebars
copy nslasherj.zip ".\BeatEmUp" || PAUSE REM Uncensored JPN version
copy pacman.zip ".\Maze" || PAUSE REM Pac-Man
copy qix2.zip ".\Puzzle" || PAUSE REM Qix II Tournament
copy quartet2a.zip ".\Action" || PAUSE REM Quartet 2-player
copy rambo3u.zip ".\STGMisc" || PAUSE REM Rambo III U.S.
copy rampart2p.zip ".\STGSingle" || PAUSE REM Rampart joystick version
copy gaiden.zip ".\BeatEmUp" || PAUSE REM Shadow Warriors U.S. version
copy simpsons2p.zip ".\BeatEmUp" || PAUSE REM The Simpsons 2 player
copy simpsons2pj.zip ".\BeatEmUp" || PAUSE REM The Simpsons 2 player JPN w/ bugfixes
copy svcsplus.zip ".\Fighting" || PAUSE REM SNK vs. Capcom Chaos Super Plus (bootleg, cast unlocked)
copy sf2rb.zip ".\Fighting" || PAUSE REM SF2CE Rainbow Edition bootleg
copy sfiiin.zip ".\Fighting" || PAUSE REM Street Fighter III: New Generation No CD
copy sfiii2n.zip ".\Fighting" || PAUSE REM Street Fighter III 2nd Impact: Giant Attack No CD 
copy sfiii3n.zip ".\Fighting" || PAUSE REM Street Fighter III 3rd Strike: Fight for the Future No CD
copy ssridersubc.zip ".\Platform" || PAUSE REM Sunset Riders 2-player
copy tmnt2po.zip ".\BeatEmUp" || PAUSE REM TMNT 2-player
copy tmnt22pu.zip ".\BeatEmUp" || PAUSE REM TMNT2 2-player
copy twincobru.zip ".\STGVert" || PAUSE REM Twin Cobra US version, slight differences
copy uccopsar.zip ".\BeatEmUp" || PAUSE REM Undercover Cops Alpha-Renewal (better graphics, more moves)
copy vendetta2pu.zip ".\BeatEmUp" || PAUSE REM Vendetta 2-player Asian version
copy xmen2pa.zip ".\BeatEmUp" || PAUSE REM X-Men 2-player
copy xmen6p.zip ".\BeatEmUp" || PAUSE REM X-Men 6-player dual-screen

It concludes with a little routine that tries to copy the popular Neo Geo and CPS2 BIOS files where they’re needed. Here’s a link to my full batch file:

>>> Link to Pastebin: Full code of ~~~TidyUp.bat <<<

All set? Run your clean-up batch file and all ROMs should finally be in place. That comforting sense of satisfaction and warmth is your brain’s anal-retentive gland spraying the good chemical. Ahhh. [/TD] [/TR] [/TABLE]

5 Likes

Step 4: AHK FTW

Home stretch now. We’re going to run two AutoHotKey scripts that

[ol] [li]Rename all your Snap and Title images to have more friendly names, which match the friendly game titles in your playlists [/li][li]Generate playlists for each folder and copy only the necessary, friendly Snap / Title images to the appropriate thumbnail folders under RetroArch [/li][/ol] Let’s call them the Friendly Image Renaming Script and the Playlist Script. Both were originally posted by Tatsuya79.

[TABLE=“width: 900, align: center”]

[B]Makin’ Images (First Script)

[/B] [TABLE=“width: 888, align: center”] [TR] [TD]We need to run Friendly Image Renaming Script first. It will rename the MAME Snap / Title images, which currently match the very short filenames of the MAME ROMs, to have nicer, human-readable titles. For example, ddragon.png will become Double Dragon (Japan).png.

This is necessary because RetroArch playlists we generate will display those “friendly” game names, extracted from a .dat file, rather than hard-to-parse ROM filenames like mdntmrdr.zip. As such, RetroArch will look in its humbnails folder for Title and Snap PNGs with that exact, “friendly” filename. It would not find or use ddragon.png even if it were present, meaning Double Dragon (Japan)'s entry in the playlist would lack thumbnail images.

You must run the script twice, once for the ~Snaps folder and once for ~Titles.

Look at the top of the code: There are three variables you need to fill in before the script can work. They are the path to your ~Snaps folder, the path you want the “friendly” renamed images to go to, and the path to a MAME .dat file of the same version as your romset. (Download the .dat file here.) [TABLE=“class: outer_border, width: 400”] [TR] [TD]AutoHotKey Basics

Install AutoHotKey. Create a blank text file and give it an .ahk extension. Open it and paste in some AHK code. Save. It is now an AutoHotKey script which will execute when double-clicked.

AHK scripts exit when finished executing. Look for the square green “H” icon in your system tray to see if any are currently running. No icons mean they finished.

Double-click the “H” icon to bring up a window showing the currently executing lines of code. Refresh with F5. More interesting: Click View -> Variables and their contents and press F5 to view the current contents of memory. See any ROMs you recognize flashing by?

[/TABLE] [/TD] [/TR] [/TABLE] I’ve filled them in to reflect our example paths. Update them with your own.

Here’s the code to paste into an .ahk file:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

;AUTOHOTKEY SCRIPT TO GENERATE FRIENDLY IMAGE NAMES FOR RETROARCH PLAYLIST USE
;"Friendly Image Renaming Script"

;### SETUP, ADD YOUR PATHS HERE

content = C:\MAME Roms\~Snaps
;### Path to folder containing MAME Snap or Title images

destination = C:\MAME Roms\~SnapsFriendly
;### Path to folder where script should place renamed images

dat = C:\MAME Roms\~MAME - ROMs (v0.176_XML).dat
;### path to a MAME ROM database file
;### example C:\files\MAME - ROMs (v0.164_XML).dat
;### get dat here http://www.emulab.it/rommanager/datfiles.php

;### TIP: If you're renaming both Snaps and Titles, make a second copy of this script, point 
;### the folder paths at the other image type, and run both at once. You'll save time.

FileRead, dat, %dat%

Loop, %content%\*.png
{

name := SubStr(A_LoopFileName,1,-4) ;trim .png

needle2 = <game name=.%name%. (isbios|isdevice)
if RegExMatch(dat, needle2) 
 continue

needle = <game name=.%name%.(?:| ismechanical=.*)(?:| cloneof=.*)(?:| romof=.*)>\R\s*<description>(.*)</description>
RegExMatch(dat, needle, datname)
if !datname1
 datname1 := name ;fallback to filename

datname1 := RegExReplace(datname1, "[/\?<>\\:*\|]","") ; replace win forbidden chars  
datname1 := RegExReplace(datname1, "'","'")       ; may need more replace like this
datname1 := RegExReplace(datname1, "&","&") 
;### datname1 := RegExReplace(datname1, " \(.*","")    ; trim stuff like "(World version 2.2)"
datname1 := RegExReplace(datname1, "\.$","") 
;list = %xx%`n%datname1% ; for troubleshooting

FileCopy, %A_LoopFileFullPath%, %destination%\%datname1%.png

}
;msgbox % list ; for troubleshooting

[TABLE=“width: 888, align: center”]

There are 36,000 Snap and 35,000 Title images, which will take the better part of an hour to rename even with two instances of the script running simultaneously.

To speed things up, Tatsuya79 suggests going into ~Snaps and ~Titles and mass-deleting images for mechanical games, casino machines, “This machine has no display,” etc. If you do, just be careful not to delete images for actual arcade games you care about. Update: Posts below have suggestions on how to speed up the actual code, but I haven’t changed anything as of yet. [TABLE=“class: outer_border, width: 360, align: center”] [TR] [TD]What is modified here?

Not much. I just made it so the script copies the renamed files into a new folder instead of renaming them in place. This lets you keep the original Snap / Title files should you wish.

[/TABLE] [/TD] [/TR] [/TABLE] [TABLE=“width: 888, align: center”]

Whatever you decide, definitely make a second copy of the script and edit in the folder paths for the other type of images. Save and execute and it will run alongside the first script. With one working on Snaps and one on Titles you’ll save a lot of time.

After you start them off check the ~SnapsFriendly and/or ~TitlesFriendly folders. Renamed images should be appearing there. If they’re not, carefully check the variable paths you entered into the script.

Done? Got tens of thousands of nicely renamed images? Great. Feel free to delete the ~Snaps and ~Titles folders unless you want them for some other project. [TABLE=“class: outer_border, width: 390, align: center”] [TR] [TD]One Other Detail…

Some games require BIOS files or CHD folders to work. You will need to copy the appropriate resources to the folders such games now reside in. For example, Neo Geo games need neogeo.zip in same folder. '90s Capcom games need qsound.zip. (I had to download it elsewhere.)

~~~TidyUp.bat, linked earlier, does a basic job of this for CPS2 and Neo Geo games.

[/TABLE] [/TD] [/TR] [/TABLE] [/TD] [/TR] [/TABLE] [TABLE=“width: 900, align: center”]

Aside: Is RetroCloning Right For You?

Something to consider.

[TABLE=“width: 888, align: center”] [TR] [TD]My RetroArch install is very crowded, with 32 console/computer playlists. It takes a long time to scroll across, and the bigger playlists cause lag as they try to load. While I was very dissatisfied with the ugly, incomplete, 3000+ item MAME playlist I generated with some other tool, I also didn’t want to cram 15+ new MAME genre playlists into an already-crowded interface.

That being the case, I decided to make a separate RetroArch config file just for MAME. I copied retroarch.cfg to retroarch MAME.cfg and created a new shortcut to launch the separate config: retroarch.exe --config “retroarch MAME.cfg”.

Once in, I changed the background color from red to blue so it’d always be immediately obvious which “install” I was using. More importantly, I decided to change two paths. I created a MAME-only playlist folder (\playlists MAME) and a MAME-only thumbnails folder ( humbnails MAME). The former kept the console/computer playlists from appearing in the MAME install, while the latter just seemed like a good way to keep organized. You can set such paths in the Directory entry under XMB’s config icon. I may redirect some other paths in the future, such as \saves.

You don’t have to do any of this, but you might want to if adding over a dozen new MAME genre playlists to your RetroArch install would feel too crowded or messy. I like having arcade stuff all separated. [TABLE=“class: outer_border, width: 300, align: center”] [TR] [TD]One Last RomLister Trick

It can be useful to generate lists of only ROM filenames or game names. To do so, choose CSV File from the results list and Preview List. Uncheck Include column headers and clear the Output Delimiter field. Choose either Description or ROM Name as desired and hit OK twice. Save as a .txt file. You now have a list of ROMs.

Several times I exported the results of two searches to CSV lists and then used Notepad++'s Compare plugin to see how they differed. Very helpful in fine-tuning searches and tracking down various exceptions and oversights in search terms.

[/TABLE] [/TD] [/TR] [/TABLE] [/TD] [/TR] [/TABLE] [TABLE=“width: 900, align: center”]

Makin’ Playlists (Second Script)

Now we’ll generate a playlist for each folder and copy just the relevant images over to the specified RetroArch thumbnails folder. Well, AHK will.

This one’s got eight variables to fill in but for subsequent runs only the top two need to be changed. At this point it should all be pretty self-explanatory. Use the same .dat file you got for the first script.

You’ll have to run this script once for each subfolder of ROMs you’ve created, updating the top two variables each time. One folder = one playlist.

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

;AUTOHOTKEY SCRIPT TO GENERATE RETROARCH MAME PLAYLISTS W/ SNAP + TITLE IMAGES
;"Playlist Script"

;### SETUP, ADD YOUR PATHS HERE
;### After the initial setup/run you'll only need to change the top 2 variables for subsequent runs

content = C:\MAME Roms\Fighting
;### Full path of a MAME ROMs folder. 
;### If you run this script multiple times with a different folder set here each time you can make 
;### multiple playlists. For ex., make folders for each genre of ROMs, populate them, and then run 
;### this script on each folder. Result: One RA playlist for each folder.

Playlist = Fighting
;### Name of playlist, no extension; this determines name of playlist file and name of related 
;### subfolder in RetroArch's thumbnails folder. Ex: Fighting   Ex: Driving   Ex: BeatEmUp
;### For instance, Fighting would result in a Fighting.lpl in \playlists and a subfolder called
;### \Fighting in 	humbnails

;### TIP: RA displays playlists in alphanumeric order. If you'd like to control the ordering,
;### prefix each playlist with a number. Ex: 01_Fighting  02_BeatEmUp  03_Action
;### This has the added bonus of making your icon image filenames conveniently cluster together.

MAMESnaps = C:\MAME Roms\~SnapsFriendly
;### Full path of MAME snap (gameplay) images with friendly names (generated with Tatsuya79's MAME 
;### image renaming script). This is optional; you only need this if you want gameplay images in RA)

MAMETitles = C:\MAME Roms\~TitlesFriendly
;### Full path of MAME title screen images with friendly names (generated with Tatsuya79's MAME 
;### image renaming script). This is optional; you only need this if you want title screen images in RA)

RAPath = C:\Emulation\RetroArch
;### Full path of Retroarch root folder  Ex: C:\Emulation\RetroArch

RAPlayFold = playlists
;### Name (not full path) of desired RetroArch playlists folder  Ex: playlists  Ex: playlists MAME

RAThumbFold = thumbnails
;### Name (not full path) of desired RetroArch thumbnails folder  Ex: thumbnails  Ex: thumbnails MAME

dat = C:\MAME Roms\~MAME - ROMs (v0.176_XML).dat
;### path to a MAME ROM database file
;### example C:\files\MAME - ROMs (v0.164_XML).dat
;### get dat here http://www.emulab.it/rommanager/datfiles.php

FileSetAttrib, -R, %RAPath%\%RAPlayFold%\%Playlist%.lpl ; remove read-only attrib from existing playlist file
FileDelete, %RAPath%\%RAPlayFold%\%Playlist%.lpl        ; clear existing playlist file
FileCreateDir, %RAPath%\%RAThumbFold%\%Playlist%\Named_Snaps  ; create thumbnail folder
FileCreateDir, %RAPath%\%RAThumbFold%\%Playlist%\Named_Titles ; create thumbnail folder
FileRead, dat, %dat%

Loop, %content%\*.zip
{
if A_LoopFileName in neogeo.zip,awbios.zip,cpzn2.zip,qsound.zip
 continue 
;### you can add names of zip files in the folder to skip in the list above

name := SubStr(A_LoopFileName,1,-4) ;trim .zip

needle2 = <game name=.%name%. (isbios|isdevice|ismechanical)
if RegExMatch(dat, needle2) 
 continue

needle = <game name=.%name%.(?:| ismechanical=.*)(?:| cloneof=.*)(?:| romof=.*)>\R\s*<description>(.*)</description>
RegExMatch(dat, needle, datname)
if !datname1
 datname1 := name ;fallback to filename

datname1 := RegExReplace(datname1, "[/\?<>\\:*\|]","") ; replace win forbidden chars  
datname1 := RegExReplace(datname1, "'","'")       ; may need more replace like this
datname1 := RegExReplace(datname1, "&","&") 
;### datname1 := RegExReplace(datname1, " \(.*","")    ; trim stuff like "(World version 2.2)"
datname1 := RegExReplace(datname1, "\.$","") 
;list = %xx%`n%datname1% ;for troubleshooting


a =
(
%A_LoopFileFullPath%
%datname1%
DETECT
DETECT
-
%Playlist%.lpl
)
if (a_index == 1)
{
 FileAppend, %a%, %RAPath%\%RAPlayFold%\%Playlist%.lpl
 FileCopy, %MAMEsnaps%\%datname1%.png, %RAPath%\%RAThumbFold%\%Playlist%\Named_Snaps
 FileCopy, %MAMEtitles%\%datname1%.png, %RAPath%\%RAThumbFold%\%Playlist%\Named_Titles
}
else
{
 FileAppend, `n%a%, %RAPath%\%RAPlayFold%\%Playlist%.lpl
 FileCopy, %MAMEsnaps%\%datname1%.png, %RAPath%\%RAThumbFold%\%Playlist%\Named_Snaps
 FileCopy, %MAMEtitles%\%datname1%.png, %RAPath%\%RAThumbFold%\%Playlist%\Named_Titles
}
}

FileSetAttrib, +R, %RAPath%\%RAPlayFold%\%Playlist%.lpl ; add read-only attrib to existing playlist file

;msgbox % list ; for troubleshooting

[TABLE=“width: 888, align: center”] [TR] [TD]The Playlist Script should finish quickly. Check out your specified \playlists folder… did the new playlist appear? How about a new subfolder under humbnails? If anything failed, carefully check the script’s variables.

All there? Great, now start RetroArch. Does the new playlist show up? Hooray! If games don’t have snap / title images press RetroPad Y button; it cycles between artwork, titles, and snaps, and it’s probably on artwork.

The script sets playlists to read-only to prevent RA from associating cores with specific games. That way you can always choose between different MAME cores, FBAlpha, etc. (RA would ideally let us disable that tracking…) [TABLE=“class: outer_border, width: 400, align: center”] [TR] [TD]What is modified here?

A lot: added six variables. The playlist name is no longer hardcoded to MAME.lpl, and the script sends it to the specified RA \playlists folder instead of spitting it out in the script’s folder. It also sets playlists to read-only.

Also added image handling, so every time the script appends an entry to the playlist file it also copies the correct, friendly Snap / Title images to the correct RA humbnails folders. (It also creates those folders.)

Tried to make the help text as clear as possible, too.

[/TABLE] [/TD] [/TR] [/TABLE] If you ever add new ROMs to a folder or otherwise change its contents just re-run the Playlist Script to create an updated playlist.

You’ll notice that the playlists have black squares for both the header and content icons. Fret not. Take a moment to celebrate your success, kick the tires a bit.

Then, if you’re feeling artistic, proceed to Step 5.[/TD] [/TR] [/TABLE] [HR][/HR]Step 5: Make it Pretty

All that remains is to make icon images for your new playlists.

The default XMB skin icons live in [B][/B]assets\xmb\monochrome\png. I use the retroactive theme so mine go in [B][/B]assets\xmb\retroactive\png.

[TABLE=“width: 900, align: center”]

[TABLE=“width: 888, align: center”] [TR] [TD]Icons are 256x256 transparent PNGs. If the playlist is called STGHori.lpl then RetroArch will search for STGHori.png (header image) and STGHori-content.png (icon next to each playlist entry).

Not much more to say! It can actually take quite a while to find suitable art and whip up nice icons.

I’ve created around 140 RetroArch MAME icons for your use, a split of maybe 80% headers and 20% content icons. Most look pretty sharp. Click below to download them.

[

[COLOR="#0d66ac"]Click to download >>> RetroArch MAME Icon Pack (Update 3) <<<](http://www.mediafire.com/file/jpbambctcdsawq4/RetroArch_MAME_Icon_Pack.zip)[/COLOR]

[TABLE=“width: 550, align: center”] [TR] [TD=“align: center”]Click for full view

[/TABLE] [/TD] [/TR] [/TABLE] It would be cool if others wanted to share their playlist icons, too. Post 'em up.[/TD] [/TR] [/TABLE] [HR][/HR]Fin

Well, that’s it. Hope this all works for you. Enjoy your spiffed-up MAME playlists!

Thanks to Tatsuya79 (and their AHK shadow posse) for coding the clever parts of those super-helpful scripts, and of course the Libretro and RetroArch developers (and community!) for their absolutely fantastic work in advancing the state of emulation.

(Btw, the max character limit for posts here is 50,000. Good to know, huh?)

5 Likes

Wow quite the nice effort you put into this guide, great work! :slight_smile:

That’s an interesting idea to cut the game library into several genre playlists. Personally I prefer having everything together for now, easier to search (and because I made it that way already!).

What I’d like to avoid those huge playlist loading lags would be to switch to glui/materialui if it comes to support thumbnails (and get the clock back!). It doesn’t load playlists automatically like xmb and is a lot faster to browse (going from an ingame quickmenu to video settings is such a pain in xmb as an example, and scrolling 8 by 8 when pushing left and right while browsing a playlist is nice too).

Anyway some great script tips I’ll come back to check here, thank you.

(PS: I hardly know how to script a bit by reading other people in that Mame playlist thread! Props to them.)

2 Likes

Great work. Stickied :slight_smile:

1 Like

Thread subscribed!

The version of the AHK scripts I’m using for MAME playlists in Lakka is somewhat mutated from the original at this point, but you might think about adopting a change from my version. Using StrReplace instead of RegExReplace to replace the illegal filename characters resulted in a substantial speedup for me.

For what it’s worth:


;### AUTOHOTKEY SCRIPT TO GENERATE MAME PLAYLIST FOR LAKKA/RETROARCH

;---------------------------------------------------------------------------------------------------------
#NoEnv                          ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input                  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%      ; Ensures a consistent starting directory.
;---------------------------------------------------------------------------------------------------------

playlistname = MAME.lpl
;### Local path to output the playlist file.
;### Should include the .lpl extension.
;### NOTE: THIS SCRIPT WILL DELETE ANY EXISTING FILE WITH THIS NAME
;### As of 5/2016 using the name "MAME.lpl" results in icons appearing for
;### MAME and its playlist entries in Lakka. Other file names may require 
;### adding icons or copying the MAME set.
;### Default: MAME.lpl

dat = MAME 078.dat
;### Example: C:\MAME\dats\MAME 078.dat
;### local path to a MAME ROM database file

romextension = .zip
;### Enter a . (dot/period) followed by the extension of the ROMs.
;### This should be .zip or .7z
romextensionlength := StrLen(romextension)     ;### automatically calculate the length of the extension

windowsroms = F:\Lakka Staging\roms\MAME 0.78
;### Example: C:\MAME 0.78 Non-Merged\roms
;### DO NOT INCLUDE A CLOSING SLASH AT THE END OF THE PATH
;### This path is a MAME ROMs folder accessible to THIS WINDOWS HOST. These 
;### ROMs should be the same set that will be used in Lakka
;### and should be of the same MAME version as the datfile.

lakkaroms = /storage/roms/MAME 0.78
;### Example: /storage/roms/MAME 0.78
;### DO NOT INCLUDE A CLOSING SLASH AT THE END OF THE PATH
;### MAME ROMs folder on the destination Lakka installation
;### You do not need to have access to these files on the machine which
;### is running this script. The path must accurately point to the location
;### of a copy of the the same ROM set used in the Windows path above.

core = /tmp/cores/mame2003_libretro.so
;### Example: /tmp/cores/mame2003_libretro.so
;### full path to the MAME core which will be executing this playlist

FileDelete, %A_ScriptDir%\%playlistname%  ;clear old MAME.lpl file if present in this directory

FileRead, dat, %dat%
rawcounter = 0

Loop, %windowsroms%\*%romextension% {

    if A_LoopFileName in (neogeo%romextension%,awbios%romextension%,cpzn2%romextension%)
        continue    ;### manually skip these bios files. you can add names of other files to skip

    filename := SubStr(A_LoopFileName,1,(StrLen(A_Loop_File_Name) - romextensionlength)) ;### trim the file extension from the name

    filter1 = <game name=.%filename%. (isbios|isdevice)
    if RegExMatch(dat, filter1)
        continue                    ;### skip if the file listed as a BIOS or device in the dat
    
    needle = <game name=.%filename%.(?:| ismechanical=.*)(?:| sourcefile=.*)(?:| cloneof=.*)(?:|  romof=.*)>\R\s*<description>(.*)</description>
    RegExMatch(dat, needle, datname)

    fancyname := datname1    ;### extract match #1 from the RegExMatch result
    if !fancyname
        fancyname := filename   ;### the file is not matched in the dat file, use the filename instead
        
    ;### Replace characters unsafe for cross-platform filenames with underscore, 
    ;### per RetroArch thumbnail/playlist convention
    fancyname := StrReplace(fancyname, "'", "'")
    fancyname := StrReplace(fancyname, "&", "_")
    fancyname := StrReplace(fancyname, "&", "_")
    fancyname := StrReplace(fancyname, "\", "_")
    fancyname := StrReplace(fancyname, "/", "_")
    fancyname := StrReplace(fancyname, "?", "_")
    fancyname := StrReplace(fancyname, ":", "_")
    fancyname := StrReplace(fancyname, "<", "_")
    fancyname := StrReplace(fancyname, ">", "_")
    fancyname := StrReplace(fancyname, ":", "_")
    fancyname := StrReplace(fancyname, "*", "_")
    fancyname := StrReplace(fancyname, "|", "_")
    
    playlistentry =
(
%lakkaroms%/%filename%%romextension%
%fancyname%
%core%
DETECT
DETECT
%playlistname%
)

    FileAppend, %playlistentry%`n, *%A_ScriptDir%\%playlistname%      ;### the asterisk before the path invokes
                                                                    ;### binary mode. binary mode plus the `n
                                                                    ;### at the end of the line equals unix encoding
}

1 Like

Really nice!

1 Like

Thanks for the nice response. Sticky, cool!

markwkidd, good tip. If I tinker with the code again I will try that. I’ve been thinking about how the second script, too, could be a lot more functional, requiring less effort from the user. Not sure I’ll have the gumption to redo it. But maybe!

I’ve been spending way too much time making icons. Just uploaded 75 new ones. They’re mostly headers, most genres still lack content icons. Decided to stick with the convention artwork for headers, sprites for content.

Here’s a glance at everything that exists so far (click for full res): In the case of future updates I’ll just post the new ones. Will hopefully fill in the less covered genres and get at least one sprite-based content icon for each category. For now, though, my wrist hurts.

[QUOTE=Alexandra;45086]markwkidd, good tip. If I tinker with the code again I will try that. I’ve been thinking about how the second script, too, could be a lot more functional, requiring less effort from the user. Not sure I’ll have the gumption to redo it. But maybe! [/QUOTE]

Thanks!

Two thoughts about thumbnails: * If you’re interested in a proposed set of ‘official’ MAME thumbnails you may want to stop by this pull request, where the script has been put to use: https://github.com/libretro/libretro-thumbnails/pull/80 * I don’t know if my version of the thumbnail renamer script would be useful to you either, but in case it is, I have modified the original to automatically rename an entire folder of thumbnails based directly on the MAME datfile rather than generating a RetroArch playlist first and then using the playlist to rename the thumbnails.

;### AUTOHOTKEY SCRIPT TO RENAME ARCADE THUMBNAILS FOR RETROARCH

;---------------------------------------------------------------------------------------------------------
#NoEnv                          ; Recommended for performance and compatibility with future AutoHotkey releases.
#Warn                              ; Enable warnings to assist with detecting common errors.
SendMode Input                  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%      ; Ensures a consistent starting directory.
;---------------------------------------------------------------------------------------------------------

;### SETUP: ADD YOUR PATHS HERE

artsource = D:\Emulation\MAME RetroArch Thumbnails\mame 037b5	itles-resized
;### Path to the source thumbnails folder on the local machine
;### DO NOT INCLUDE A CLOSING SLASH AT THE END OF THE PATH
;### Example: C:\MAME 0.78 images	itles

processed = D:\Emulation\MAME RetroArch Thumbnails\MAME Onmnibus Thumbnails\Named_Titles
;### NOTE: THIS FOLDER MUST EXIST BEFORE THE SCRIPT IS EXECUTED
;### Path to the destination thumbnail folder on the local machine
;### DO NOT INCLUDE A CLOSING SLASH AT THE END OF THE PATH
;### Example C:\MAME 0.78 images\Named_Titles

dat = D:\Emulation\Original ROM Sets\MAME 0.37b5 Non-Merged\MAME 0.37b5.dat
;### Example: C:\MAME\dats\MAME 078.dat
;### local path to a MAME ROM database file

if !FileExist(dat) or !FileExist(artsource) or !FileExist(processed)
 return     ;### If any of these files and folders desn't exist, exit the script

;### Delete old 'ummatched' log file if it exists 
FileDelete, Unmatched Thumbnails - %dat%.log

FileRead, datcontents, %dat%
FileDelete, %processed%\Unmatched Thumbnails.log    ;### Delete old 'ummatched' log file if it exists
rawcounter = 0
A_Loop_File_Name = 0

Loop, %artsource%\*.png {
 
    SplitPath, A_LoopFileName,,,,filename     ;### trim the file extension from the name

    needle = <game name=.%filename%.(?:| ismechanical=.*)(?:| sourcefile=.*)(?:| cloneof=.*)(?:|  romof=.*)>\R\s*<description>(.*)</description>
    RegExMatch(datcontents, needle, datname)

    fancyname := datname1    ;### extract match #1 from the RegExMatch result
    
    if !fancyname {
        fancyname := filename   ;### the image filename/rom name is not matched in the dat file
         FileAppend, Unmatched Source %artsource%\%filename%.png`n`n, %processed%\Unmatched Thumbnails.log           ;for error checking
        continue                 ;### skip to the next image
    }
    
    ;### Replace characters unsafe for cross-platform filenames with underscore, 
    ;### per RetroArch thumbnail/playlist convention
    fancyname := StrReplace(fancyname, "'", "'")
    fancyname := StrReplace(fancyname, "&", "_")
    fancyname := StrReplace(fancyname, "&", "_")
    fancyname := StrReplace(fancyname, "\", "_")
    fancyname := StrReplace(fancyname, "/", "_")
    fancyname := StrReplace(fancyname, "?", "_")
    fancyname := StrReplace(fancyname, ":", "_")
    fancyname := StrReplace(fancyname, "<", "_")
    fancyname := StrReplace(fancyname, ">", "_")
    fancyname := StrReplace(fancyname, ":", "_")
    fancyname := StrReplace(fancyname, "*", "_")
    fancyname := StrReplace(fancyname, "|", "_")

    destinationfile := processed . "`\" . fancyname . ".png"
;    if FileExist(destinationfile)
;    { 
;    continue    ;### skip onward if this file already exists
;    }    
    FileCopy, %artsource%\%filename%.png, %destinationfile% , 1
}

Can someone link to controls.xml? The site appears to be down that usually hosts it.

Here you go, uploaded it to Mediafire. It is version 0.141.1, the latest version at this time.

Thanks Alexandra! Worked great. I didn’t go through all the steps just yet - for now I just used this to cull a massive amount of ROMs :slight_smile: Such an amazing shortcut to get rid of all the silly dupes etc that bloat MAME sets nowadays.

Icon pack updated with 15 new headers. Taking a break for real this time. :stuck_out_tongue:

Cool guide!

I’ll add a few optimization notes on the AutoHotKey processing in step 4. Your “Friendly Image Renaming Script” copies and renames all of the 36K + 35K images. Overkill since earlier steps filtered out a ton of games. A quicker approach is to loop over roms in the created subfolders and only copy/rename their corresponding images. That would take a bigger rewrite. But here are three quicker tweaks

First put

 SetBatchLines -1

at the top of the Friendly Image Renaming Script to increase the script speed, https://autohotkey.com/docs/commands/SetBatchLines.htm

Second slim down the dat file with the below code (takes only a few seconds) and then use “~slim.dat” in Friendly Image Renaming Script instead

 SetBatchLines, -1
x = C:\MAME Roms\~MAME - ROMs (v0.176_XML).dat
y = C:\MAME Roms\~slim.dat
Loop, Read, %x%, %y%
{
If (InStr(A_LoopReadLine, "<game name=") or InStr(A_LoopReadLine, "<description>")) 
 FileAppend %A_LoopReadLine%`n
}

With those two changes to the Friendly Image Renaming Script the time to rename 200 images dropped from 27 to 5-6 seconds. So your one hour might drop to 10-15 minutes or so.

But it gets better. We can filter out some obviously unwanted images before running the Friendly Image Renaming Script. For example the snaps set pS_snap_fullset_170.zip has about 20K snaps with the MAME mechanical/screenless/device placeholder image. We can filter them by filesize and move them to another folder (also only takes a few seconds).

;57825 bytes mechanical  9000 images
;56475 bytes device     2000 images
;56467 bytes device     1000 images
;53466 bytes screenless system 9000 images
;that leaves ~14000 images in pS_snap_fullset_170.zip

FileCreateDir, C:\MAME Roms\~SnapsSkip\
Loop, Files, C:\MAME Roms\~Snaps\*.png
{
FileGetSize, s, % A_LoopFileFullPath
if (s==57825) or (s==56475) or (s==56467) or (s==53466)
 FileMove, % A_LoopFileFullPath , C:\MAME Roms\~SnapsSkip\
}

With all these three tweaks applied the Friendly Image Renaming Script took 2 minutes to process the pS_snap_fullset_170.zip on my system.

edit:

Here is Alexandra’s script with these two tweaks added in

 #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines -1 ;max script speed 

;AUTOHOTKEY SCRIPT TO GENERATE FRIENDLY IMAGE NAMES FOR RETROARCH PLAYLIST USE
;"Friendly Image Renaming Script"

;### SETUP, ADD YOUR PATHS HERE

content = C:\MAME Roms\~Snaps
;### Path to folder containing MAME Snap or Title images

destination = C:\MAME Roms\~SnapsFriendly
;### Path to folder where script should place renamed images

dat = C:\MAME Roms\~MAME - ROMs (v0.176_XML).dat

;### path to a MAME ROM database file
;### example C:\files\MAME - ROMs (v0.164_XML).dat
;### get dat here http://www.emulab.it/rommanager/datfiles.php

;### TIP: If you're renaming both Snaps and Titles, make a second copy of this script, point 
;### the folder paths at the other image type, and run both at once. You'll save time.

;### slim down the dat file to speed up processing
SplitPath, dat, datfolder
slimdat := datfolder "\~slim.dat"

if !FileExist(datfolder "\~slim.dat")
{
Loop, Read, %dat%, %slimdat%
If (InStr(A_LoopReadLine, "<game name=") or InStr(A_LoopReadLine, "<description>")) 
 FileAppend %A_LoopReadLine%`n
}

;### filter out unwanted snap png by size in bytes to speed up processing
;57825 bytes mechanical 9000 images
;56475 bytes device     2000 images
;56467 bytes device     1000 images
;53466 bytes screenless system 9000 images
;that leaves ~14000 images in pS_snap_fullset_170.zip

SplitPath, content, contentroot
FileCreateDir, %contentroot%\~SnapsSkip\
Loop, Files, %content%\*.png
{
FileGetSize, s, % A_LoopFileFullPath
if (s==57825) or (s==56475) or (s==56467) or (s==53466)
 FileMove, % A_LoopFileFullPath , %contentroot%\~SnapsSkip\
}

;### needed: a version of the above filter/move code for the title png files

FileRead, dat, %slimdat%

Loop, %content%\*.png
{

name := SubStr(A_LoopFileName,1,-4) ;trim .png

needle2 = &lt;game name=.%name%. (isbios|isdevice)
if RegExMatch(dat, needle2) 
 continue

needle = &lt;game name=.%name%.(?:| ismechanical=.*)(?:| cloneof=.*)(?:| romof=.*)&gt;\R\s*&lt;description&gt;(.*)&lt;/description&gt;
RegExMatch(dat, needle, datname)
if !datname1
 datname1 := name ;fallback to filename

datname1 := RegExReplace(datname1, "[/\?&lt;&gt;\\:*\|]","") ;replace win forbidden chars  
datname1 := RegExReplace(datname1, "'","'")  ;may need more replace like this
datname1 := RegExReplace(datname1, "&","&") 
;### datname1 := RegExReplace(datname1, " \(.*","")        ;trim stuff like "(World version 2.2)"
datname1 := RegExReplace(datname1, "\.$","") 
;list = %xx%`n%datname1% ;for troubleshooting

FileCopy, %A_LoopFileFullPath%, %destination%\%datname1%.png

}
;msgbox % list  ;for troubleshooting

Great howto @Alexandra!

Some of us don’t use windows though, so RomLister is hard to use. Would you mind sharing the .bat files, playlists or anything else in text format that has the rom names together with the categories?

If you can share that I’ll write some small scripts that makes it useful on raspberry pie/linux.

Thanks! And absolutely. I actually had intended to update with an “easy mode” method that just supplies my batch files and lets 'em rip. I’ll put that together soon.

Great, I’ll try to be patient :wink:

Hey, I tried all this and I’m very gratefull! I had tried RomLister before, but I never figured out how powerful it could be when feeded all the information it asks for. Most of all, thanks for taking the time and explaining everything step by step (instead of just saying “here’s my BATs in case you need them” or something)

I do have a question though. What happens with required BIOS?

Example, you need qsound.zip for (some? most?) CPS2 games. Since I have my games separated by folders (ex: “STGVert” for, say, “19XX”, so “roms/STGVert” will be my rompath whenever I run this game), now they’re separated from their bios file, and RetroArch has no way to find them.

So my question is:

  • Is there a workaround, like having your BIOS files somewhere else RetroArch can read them (does it check “system” for bios?)
  • Or should I simply start again by building a Non-Merged set where every rom has all required files in itself INCLUDING system bios?

[QUOTE=spinningacorn;48389]Hey, I tried all this and I’m very gratefull! I had tried RomLister before, but I never figured out how powerful it could be when feeded all the information it asks for. Most of all, thanks for taking the time and explaining everything step by step (instead of just saying “here’s my BATs in case you need them” or something)

I do have a question though. What happens with required BIOS?

Example, you need qsound.zip for (some? most?) CPS2 games. Since I have my games separated by folders (ex: “STGVert” for, say, “19XX”, so “roms/STGVert” will be my rompath whenever I run this game), now they’re separated from their bios file, and RetroArch has no way to find them.

So my question is:

  • Is there a workaround, like having your BIOS files somewhere else RetroArch can read them (does it check “system” for bios?)
  • Or should I simply start again by building a Non-Merged set where every rom has all required files in itself INCLUDING system bios?[/QUOTE]

Hey… it’s funny that you ask this question, because I was literally dealing with the same issue this past weekend and I had written my own scripts to generate playlists prior to discovering this thread… I came up with a solution that worked for me.

You can check out my script here: https://github.com/singularity098/Generate-MAME-Playlist-for-RetroArch

You could follow the normal instructions for that script, but also change this line from $false to $true, like this:

$writeBiosList=$true

With that done, the script will generate a file “_BIOSList.txt” which should be a list of any file that was tagged as being a device which is not runnable (pretty much a BIOS). So from there you could do something like this to copy all of those files into another dir:

  1. Copy the _BIOSList.txt file that you generated to your main ROMs directory.
  2. Open PowerShell.
  3. Navigate to the ROMs directory with this command: cd ‘<replace with your roms dir>’
  4. Use the BIOSList.txt file to copy all files out of that directory with a command like this: [B]get-content ._BIOSList.txt | foreach {copy-item $ ‘<replace with your destination dir>’}[/B]

It’s a little clunky but it should work. For me I’m dealing with the most recent version of MAME and this produces 400 files (about 9 MB) which I then just drop in with my trimmed down romset, and everything seems to work.

This might depend on which version of MAME you’re trying to work with though. To be honest I am pretty new to this and am still learning about MAME. I see that the older MAME versions have much less metadata in their dat files, and so for older versions of MAME I don’t see the xml node for “isdevice” or “runnable”… and therefore on those files, my script would produce an empty bios list file. :frowning:

As a matter of fact, I am looking at a MAME 078 dat today and I search the entire file for “qsound” and it does not appear in the file… so I am no expert on these files and I don’t even understand how that’s possible. But that method should work for you if using a more recent MAME version.

EDIT: Errr… I may have somewhat misunderstood your problem, but maybe this would be helpful anyway. :stuck_out_tongue:

@spinningacorn Very happy you found this useful!

Regarding your proposed solutions, I don’t know if #1 is possible, and #2 is unnecessary.

I just used my very modest knowledge of common BIOSes to judge which folders needed BIOS .zips dropped in. For example, any folder with a Neo Geo game got neogeo.zip. Any folders with CPS2 roms got qsound.zip. etc. These BIOS files are largely tiny (oops, oxymoron) so the wasted disk space is negligible.

Later, if a game fails to load, a quick check online can tell you if it’s due to a missing BIOS or another reason. I don’t remember if the RomLister database can tell you if a game requires a BIOS… maybe it does? RA MAME cores may also spit out relevant error messages somewhere, but I’m not up on that.

Remember you can get a list of all the BIOS files RomLister knows about with the search B[/B], which can be made into the handy macro @B. I made a BIOS-only folder for easy grabbin’ when needed.

That help?

@chrisq So sorry to keep you waiting. Haven’t had much supernerd bandwidth lately. I haven’t forgotten.

[QUOTE=Alexandra;48604]@spinningacorn I just used my very modest knowledge of common BIOSes to judge which folders needed BIOS .zips dropped in. For example, any folder with a Neo Geo game got neogeo.zip. Any folders with CPS2 roms got qsound.zip. etc. These BIOS files are largely tiny (oops, oxymoron) so the wasted disk space is negligible.[/QUOTE]

Yeah, I figured this would be the most obvious fix, and that’s what I’m doing :slight_smile: I merely was curious what was your personal approach to this, since you didn’t mention it in your guide…

I later realized there was a exclusion list on the AHK file. I pretty much copied every single BIOS files on each category folder and added all of them on the exclusion list of the AHK. Solved.