January 25, 2008 Shuffle | ||||
---|---|---|---|---|
| ||||
For fun, I ordered a new car stereo that would play music from an SD card or USB stick(rather than from CD), and installed it over the weekend. The problem is loading songs onto the SD card from my home music server, which I like to hear played at random. The solution is a simple D program, shuffle, which will randomly copy music files to an SD card until it fills up. Have some fun with it! ---------------------------- /* Program to randomly copy music files from source to destination device. * Written in the D programming language. * Written by Walter Bright, http://www.digitalmars.com * Placed into the Public Domain. */ import std.file; import std.stdio; import std.string; import std.c.stdlib; import std.path; import std.random; int main(string[] args) { if (args.length != 3) { writefln("Usage: shuffle fromdir todir"); exit(1); } auto fromdir = args[1]; auto todir = args[2]; /* Recursively search for all the mp3 and wma files in directory fromdir * and put them into files[] */ string[] files; bool callback(DirEntry *de) { if (de.isdir) listdir(de.name, &callback); // recurse into subdirectories else { // Collect only files with mp3 and wma extensions auto ext = getExt(de.name); if (fnmatch(ext, "mp3") || fnmatch(ext, "wma")) files ~= de.name; } return true; // keep going } std.file.listdir(fromdir, &callback); writefln(files.length, " music files"); /* The loop will normally quit via an exception when the target device * is full. But if there are not enough files in the source to fill * up the target, the loop ensures it will still eventually quit. */ for (size_t i = 0; i < files.length; i++) { auto j = std.random.rand() % files.length; auto fromfile = files[j]; auto tofile = std.path.join(todir, basename(fromfile)); writefln("%s => %s", fromfile, tofile); std.file.copy(fromfile, tofile); } writefln("Done"); return 0; } |
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> For fun, I ordered a new car stereo that would play music from an SD card or USB stick(rather than from CD), and installed it over the weekend. The problem is loading songs onto the SD card from my home music server, which I like to hear played at random.
>
> The solution is a simple D program, shuffle, which will randomly copy music files to an SD card until it fills up. Have some fun with it!
> ----------------------------
>
> /* Program to randomly copy music files from source to destination device.
> * Written in the D programming language.
> * Written by Walter Bright, http://www.digitalmars.com
> * Placed into the Public Domain.
> */
>
>
> import std.file;
> import std.stdio;
> import std.string;
> import std.c.stdlib;
> import std.path;
> import std.random;
>
> int main(string[] args)
> {
> if (args.length != 3)
> { writefln("Usage: shuffle fromdir todir");
> exit(1);
> }
> auto fromdir = args[1];
> auto todir = args[2];
>
> /* Recursively search for all the mp3 and wma files in directory fromdir
> * and put them into files[]
> */
> string[] files;
> bool callback(DirEntry *de)
> {
> if (de.isdir)
> listdir(de.name, &callback); // recurse into subdirectories
> else
> {
> // Collect only files with mp3 and wma extensions
> auto ext = getExt(de.name);
> if (fnmatch(ext, "mp3") || fnmatch(ext, "wma"))
> files ~= de.name;
> }
> return true; // keep going
> }
> std.file.listdir(fromdir, &callback);
>
> writefln(files.length, " music files");
>
> /* The loop will normally quit via an exception when the target device
> * is full. But if there are not enough files in the source to fill
> * up the target, the loop ensures it will still eventually quit.
> */
> for (size_t i = 0; i < files.length; i++)
> {
> auto j = std.random.rand() % files.length;
> auto fromfile = files[j];
> auto tofile = std.path.join(todir, basename(fromfile));
> writefln("%s => %s", fromfile, tofile);
> std.file.copy(fromfile, tofile);
> }
>
> writefln("Done");
> return 0;
> }
And what would be the Tango equivalent, I wonder? ;)
|
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Reimer | John Reimer wrote:
> And what would be the Tango equivalent, I wonder? ;)
What I'd like to do is collect a bunch of simple "cookbook" utilities like this that fit nicely into a single file, which can be put on the website to help people get started with D. I have several floating around my hard disk.
|
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> John Reimer wrote:
>> And what would be the Tango equivalent, I wonder? ;)
>
>
> What I'd like to do is collect a bunch of simple "cookbook" utilities like this that fit nicely into a single file, which can be put on the website to help people get started with D. I have several floating around my hard disk.
It's a great idea. These sort of snippets are probably practical learning tools for those interested in the language.... might turn out to be a good compilation for a d book someday, too :) (The book "Practical Common Lisp" comes to mind as an example of this style of teaching a language).
-JJR
|
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Fri, 25 Jan 2008 07:35:04 +0300, Walter Bright <newshound1@digitalmars.com> wrote: > The solution is a simple D program, shuffle, which will randomly copy music files to an SD card until it fills up. Have some fun with it! I think than the code could be yet more compact, simple and script-like if std.file (or std.path) module will contain something like Dir.glob from Ruby (http://www.ruby-doc.org/core/classes/Dir.html#M002347) > /* Program to randomly copy music files from source to destination device. > * Written in the D programming language. > * Written by Walter Bright, http://www.digitalmars.com > * Placed into the Public Domain. > */ > > > import std.file; > import std.stdio; > import std.string; > import std.c.stdlib; > import std.path; > import std.random; > > int main(string[] args) > { > if (args.length != 3) > { writefln("Usage: shuffle fromdir todir"); > exit(1); > } > auto fromdir = args[1]; > auto todir = args[2]; > > /* Recursively search for all the mp3 and wma files in directory fromdir > * and put them into files[] > */ auto files = std.file.glob( std.path.join( fromdir, "**/*.{mp3,wma}" ) ); > > writefln(files.length, " music files"); > > /* The loop will normally quit via an exception when the target device > * is full. But if there are not enough files in the source to fill > * up the target, the loop ensures it will still eventually quit. > */ > for (size_t i = 0; i < files.length; i++) > { > auto j = std.random.rand() % files.length; > auto fromfile = files[j]; > auto tofile = std.path.join(todir, basename(fromfile)); > writefln("%s => %s", fromfile, tofile); > std.file.copy(fromfile, tofile); > } > > writefln("Done"); > return 0; > } -- Regards, Yauheni Akhotnikau |
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to eao197 | eao197 wrote:
> I think than the code could be yet more compact, simple and script-like if std.file (or std.path) module will contain something like Dir.glob from Ruby (http://www.ruby-doc.org/core/classes/Dir.html#M002347)
I agree.
|
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> eao197 wrote:
>> I think than the code could be yet more compact, simple and script-like if std.file (or std.path) module will contain something like Dir.glob from Ruby (http://www.ruby-doc.org/core/classes/Dir.html#M002347)
>
> I agree.
Part of it already exists in 2.0, in the std.file.dirEntries and .DirIterator code. It needs to take a delegate or other filter mechanism to gain the rest of the power. But as is it'd simply the example of a bit of it (untested).
string[] files;
foreach (DirEntry de; dirEntries(fromdir, SpanMode.depth))
{
// Collect only files with mp3 and wma extensions
auto ext = getExt(de.name);
if (fnmatch(ext, "mp3") || fnmatch(ext, "wma"))
files ~= de.name;
}
Later,
Brad
|
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote: [...] > for (size_t i = 0; i < files.length; i++) > { > auto j = std.random.rand() % files.length; > auto fromfile = files[j]; > auto tofile = std.path.join(todir, basename(fromfile)); > writefln("%s => %s", fromfile, tofile); > std.file.copy(fromfile, tofile); > } Here you are copying duplicate files over and over. You don't see duplicates because a file copy will overwrite the previously written file, but if you have enough space on the destination device you'll get less files on the destination than those on the source, because duplicates will overwrite. I've found players that implement the shuffle function this way: the pseudo random generator always "prefers" a certain subset of the songs and will play them frequently, while other songs are rarely selected (if ever). A real "shuffle" function should generate the same list of songs that the source contains, changing only the order. Ciao -- Roberto Mariottini, http://www.mariottini.net/roberto/ SuperbCalc, a free tape calculator: http://www.mariottini.net/roberto/superbcalc/ |
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Roberto Mariottini | Roberto Mariottini wrote: > Here you are copying duplicate files over and over. You don't see duplicates because a file copy will overwrite the previously written file, but if you have enough space on the destination device you'll get less files on the destination than those on the source, because duplicates will overwrite. True, the algorithm kinda sucks, but the program was created where I have way, way more songs on the server than will fit on the SD card. So even if it copies the same file multiple times, it doesn't affect the result (except that it takes longer). My defense is I only spent a few minutes writing it <g>. > I've found players that implement the shuffle function this way: the pseudo random generator always "prefers" a certain subset of the songs and will play them frequently, while other songs are rarely selected (if ever). > A real "shuffle" function should generate the same list of songs that the source contains, changing only the order. I agree, a much better algorithm would be to shuffle the files[] array, then sequentially write the shuffled result. |
January 25, 2008 Re: Shuffle | ||||
---|---|---|---|---|
| ||||
Posted in reply to Roberto Mariottini | Roberto Mariottini wrote: > A real "shuffle" function should generate the same list of songs that the source contains, changing only the order. Here's a revised one: /* Program to randomly copy music files from source to destination device. * Written in the D programming language. * Written by Walter Bright, http://www.digitalmars.com * Placed into the Public Domain. */ import std.file; import std.stdio; import std.string; import std.c.stdlib; import std.path; import std.random; int main(string[] args) { if (args.length != 3) { writefln("Usage: shuffle fromdir todir"); exit(1); } auto fromdir = args[1]; auto todir = args[2]; /* Recursively search for all the mp3 and wma files in directory fromdir * and put them into files[] */ string[] files; bool callback(DirEntry *de) { if (de.isdir) listdir(de.name, &callback); // recurse into subdirectories else { // Collect only files with mp3 and wma extensions auto ext = getExt(de.name); if (fnmatch(ext, "mp3") || fnmatch(ext, "wma")) files ~= de.name; } return true; // keep going } std.file.listdir(fromdir, &callback); writefln(files.length, " music files"); /* Shuffle the files[] array */ for (size_t i = 0; i < files.length; i++) { auto j = std.random.rand() % files.length; // swap [i] and [j] auto tmp = files[i]; files[i] = files[j]; files[j] = tmp; } /* Sequentially fill the target until done or it quits with an * exception when the device is full. */ foreach (fromfile; files) { auto tofile = std.path.join(todir, basename(fromfile)); writefln("%s => %s", fromfile, tofile); std.file.copy(fromfile, tofile); } writefln("Done"); return 0; } |
Copyright © 1999-2021 by the D Language Foundation