Jump to page: 1 25  
Page
Thread overview
Shuffle
Jan 25, 2008
Walter Bright
Jan 25, 2008
John Reimer
Jan 25, 2008
Walter Bright
Jan 25, 2008
John Reimer
Jan 25, 2008
Saaa
Jan 25, 2008
Lars Noschinski
Jan 26, 2008
Lars Ivar Igesund
Jan 25, 2008
eao197
Jan 25, 2008
Walter Bright
Jan 25, 2008
Brad Roberts
Jan 25, 2008
Roberto Mariottini
Jan 25, 2008
Walter Bright
Jan 25, 2008
Sean Kelly
Jan 25, 2008
Walter Bright
Jan 25, 2008
Oskar Linde
Jan 25, 2008
Bill Baxter
Jan 25, 2008
Walter Bright
Jan 26, 2008
Anders Bergh
Jan 26, 2008
Walter Bright
Jan 25, 2008
bearophile
Jan 25, 2008
Lars Ivar Igesund
Jan 25, 2008
BCS
Jan 25, 2008
Bill Baxter
Jan 25, 2008
Frits van Bommel
Jan 25, 2008
Walter Bright
Jan 25, 2008
Frits van Bommel
Jan 26, 2008
Walter Bright
Jan 27, 2008
Frits van Bommel
Jan 27, 2008
Walter Bright
Jan 27, 2008
Kris
Jan 27, 2008
Bill Baxter
Jan 28, 2008
Sean Kelly
Jan 28, 2008
Frits van Bommel
Jan 28, 2008
Walter Bright
Jan 28, 2008
Sean Kelly
Jan 28, 2008
Frits van Bommel
Jan 28, 2008
Sean Kelly
Jan 28, 2008
Bill Baxter
Jan 29, 2008
Sean Kelly
Jan 27, 2008
0ffh
Jan 27, 2008
Tyro[a.c.edwards]
Jan 27, 2008
Tyro[a.c.edwards]
January 25, 2008
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
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
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
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
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
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
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
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
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
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;
}
« First   ‹ Prev
1 2 3 4 5