Batch down-sampling lots of MP3 files

I had to convert about 1,100 mp3 files from 44.1 kHz to 22.05 kHz so I could get them from a total of 6 gigabytes to 3 gigabytes. I just thought I would share my process.

First I had to decide what software to use. There are two that came to mind: FFmpeg and LAME. I primarily use Windows 10, but I also administer several Linux systems. I try to pick whichever one will be most efficient. For tasks I do on my own computer, I sometimes do it “natively” in Windows, and sometimes I use the Windows Subsystem for Linux, which is a full-blown Debian installation.

This time, however, I just did it in Windows. Here is the batch file I wrote to do it. I will include comments afterward. The thing to know is that the folders with the audio all have the format NN-LLL (N=number; L=letter).

  1. @echo off

  2. for /d %%I in (??-???) do (
  3.  for %%J in (%%I\*.mp3) do (
  4.   if not exist _22kHz\%%~nxJ (
  5.    ffmpeg -i %%J -ac 1 -ab 64000 -ar 22050 _22kHz\%%~nxJ
  6.   )
  7.  )
  8. )

I put it in a numbered list so I can refer to the line numbers.

Line 3 says to get a list of all directories that have the format XX-XXX and put them in a variable called ‘I.’ I often pick ‘I’ because that's what the examples at the end of “for /?” in command prompt use, so it's a no-brainer. The ‘/d’ is necessary because the ‘for’ command will ignore directories by default.

Line 4 looks in the directory stored in variable ‘I’ and gets a list of all the mp3 files and stores them (with pathname) in the variable ‘J.’

Line 5 indicates that my output folder is called ‘_22kHz.’ I had manually created this folder (an important step!). So it says that if the file doesn't already exist in that folder, go ahead and run line 6. The ~nx is important because it basically strips the full path name of the file and gives you just the file name, so we can accurately check for it.

Line 6 is the actual FFmpeg command to convert to 64k bit rate at 22.05 kHz sampling. It reads the file in the ‘J’ variable and outputs it to the new ‘_22kHz’ folder.

Workaround for “Windows AD domain is the same as my company’s primary DNS domain name”

I have seen many companies over the years who have their internal domain set as the same domain that their corporation uses publicly. For example, if my company is Example, Inc, my primary web and e-mail presence might be example.com. When my Windows NT 3.5 domain was set up in 1997, we called it EXAMPLE, as it seemed logical. When Windows 2000 came out and we upgraded to Active Directory, it became logical to create example.com as the AD DNS Name. The recommendation is to NOT do that, but for many it was done before the recommendations were widely published (or they didn't think to look), and they simply have to live with it.

Years ago, most non-technical users (in my estimation) believed there was something magical about the “www” portion of a web address. For example, “www.example.com” was any given company’s web site. However, more and more people are dropping the “www” and just going to “example.com”. It’s the responsibility of the IT people (DNS and web administrators) to make sure the DNS A record for @ (domain root) points to the web server address, and the web admin must make sure the site answers for www.example.com and example.com and presents the same content to both (or redirects one to the other).

Here comes the problem in the first paragraph. For one thing, it requires split DNS: there is a public “version” of all the example.com records, and a private version. Within an Active Directory infrastructure, the private version of example.com (with no host name specified) should resolve to the IP address of all the domain controllers. For example, if I have three domain controllers, nslookup example.com should return 10.1.1.5, 10.1.2.5, and 10.1.3.5, assuming those are the addresses of my DCs. Most likely, the domain controllers are also not hosting the public web site (and they sure shouldn’t be!). This means that if I’m inside the network, pointing to internal DNS servers and I type example.com into my web browser, I won’t get anywhere.

The simplest solution I found in that case is to redirect the request to www.example.com, which can point to the public address of the public web server--what people expect to hit when they type in example.com internally. To do this, we could install IIS on every domain controller and set up a HTTP 301 or 302 redirection to www.example.com. But installing IIS on every domain controller adds overhead, etc, to the box, as well as lots of new DLLs and other things to introduce security problems (anyone remember Code Red?).

Another solution is to use ncat and NSSM (the Non-Sucking Service Manager). ncat can sit in memory with the help of NSSM and simply redirect http queries to the box to www.example.com. All that is needed is two exe files and one batch file to be copied to each server. Here’s how it could be done.

redir.cmd
@echo off
echo HTTP/1.1 302 Found >%temp%\redir.txt
echo Location: http://www.example.com/ >>%temp%\redir.txt
c:\redir\ncat -l 80 < %temp%\redir.txt


Put all three files (ncat.exe, nssm.exe, redir.cmd) in c:\redir. Then install the service using nssm with the following command (run as administrator):

nssm install "Web Redirector" c:\redir\redir.cmd

You could even deploy it to all your DCs remotely. You could do it your way, or using something like this:

deploywebredir.cmd
@echo off

setlocal ENABLEDELAYEDEXPANSION
set DCLIST=\\

for /f "delims=. " %%a in ('nltest /dclist:%USERDNSDOMAIN% ^|findstr /c:"[DS]"') do (
 md \\%%a\c$\redir
 for %%b in (ncat.exe nssm.exe redir.cmd) do copy /y %%b \\%%a\c$\redir
 set DCLIST=!DCLIST!%%a,
)

set DCLIST=%DCLIST:~0,-1%

psexec %DCLIST% -e c:\redir\nssm install "Web Redirector" c:\redir\redir.cmd


If you’re not familiar with psexec or nltest, you should get up to speed! Just search for them in your favorite search engine.

If you want to make this more secure, define a user with no particular privileges (besides Log on as a Service) and set the service to run as that user. Even if someone buffer overruns ncat.exe, they will only have basic user access.

Kindle URI Format

As many people, I am an avid user of Amazon Kindle. My family of three has two Kindles (2.0 and Paperwhite), my wife and I each have the app on our smart phones, and we each have Kindle for Windows on our laptops.

I was writing a document in Word and I wanted to be able to refer to particular sections of a Kindle book. I had a heck of a time figuring out the URI format, but I eventually put enough pieces together to give me what I wanted.

Here it is:

     kindle://book?action=open&asin=B003G4W49C&location=1178

There are more options than this, but this gets you to a particular location... it is made up of three components:
  1. action = open ... open the book
  2. asin = book identifier; you can find this in any number of ways. The easiest I've found is this:
    1. Go to your Kindle Content directory. Mine is C:\Users\Matt\Documents\My Kindle Content
    2. Then run findstr /m "Ender's Game" *.azw where in this case you would replace "Ender's Game" with your book's title.
  3. location = xxxxx ... whatever location you want to go to

Just thought I'd share...

Regular Expression for Book/Chapter of the Bible

What perl-compatible regular expression (PCRE) could match books/chapters of the bible?
How about this one:

/(^[123]?(\s+)?[a-zA-Z\s]+)(\s+)?([0-9]+)/




Everything between the first set of parenthesis is the book name. The parenthesis are done so we can pass the variables separately on to an array. This is a common task in working with PCRE, but for simply matching a pattern, may or may not be necessary. Though the second set, putting the \s+ in parenthesis, is for grouping as opposed to passing.

^[123]?
First we have to see if it is one of the books that starts with (^) a 1, 2, or 3 (e.g., 1 Chronicles, 3 John). The question-mark means that it's optional, because most books of the bible don't have those.

(\s+)?
Next we have to check if there is a space between that and the book name, because when somebody is searching for a book of the bible, they may get lazy (like me) and not put in a space. Again, it's optional as to whether or not it's there, so we use a question-mark.

[a-zA-Z\s]+
Next we have to check for all variations of capital or small letters, and we need to allow spaces as well for books like "Song of Solomon" (actually that's the only one with a space in it). Instead of the question-mark we have the plus, because at least one of these is required. You could also use [\p{L}\s]+ in PCRE, where \p{L}, or it's long form, \p{Letter} indicates a letter from any language.

The second set of parenthesis is the chapter...

(\s+)?
Again, the space (or more than one space for that matter) is optional between the book name and the chapter.

([0-9]+)
A chapter. At least one chapter is required (the + symbol).

Pretty easy, and honestly I put this blog entry in for myself to quickly refer to in case I have documented all my code badly (which I have!).

Humility and Resisting the Devil

First blog entry in over a year...

I was reading Luke 4:12, where the devil departed from tempting Jesus "until an opportune time." This is important to remember... that the devil is always looking for an opportune time. Because you have resisted him once (James 4:7), that doesn't mean he won't be back in the near future, as he is always on the prowl looking for someone to devour (1 Peter 5:8).

Interesting that both James 4:6-7 and 1 Peter 5:6-8 talk about humility just before they talk about resisting the devil... reminds me too of what I once heard someone say in a talk: The devil demanded to sift the apostles as wheat (Luke 22:31), which happened immediately after the argument about who was to be the greatest. And the "you" used in that verse is the plural one, probably meaning those involved in the conversation. The devil seized the opportunity where they were trying to be great in order to demand to have his way with them. And Jesus doesn't say, "I have prayed for you so he can't have you," because he knew the devil had a right to demand what what he was demanding. Instead Jesus said, "I have prayed for you [singular] that your [singular] faith may not fail. And when you have turned again, strengthen your brothers" (ESV). Jesus prayed specifically for Peter, the rock, that he would make it through this trial, then lead his brothers through it as well. And the greatest trial of their lives was just about to begin 14 verses later.

Here's my point (sometimes in my rambling I forget to get back there): If we are being severely tempted by the devil, let's resist him, but not forgot to ensure or confess that there be no seed of pride in us.

P.S., If you want more of my thoughts on Luke 22:31, read on.

It's interesting that the devil demanded (Greek: exētēsato) to sift Peter & the apostles as wheat. He had a right to do that. According to most modern translations, Jesus says that he prayed for Peter's recovery, yet the word used in Greek is "edeēthēn," which is not the word used for prayer anywhere else. Its only other usage is in Luke 9:40 where the man begged the disciples to cast the demon out of his son, but they were unable to. This tells me that the devil had a right to demand Peter and the apostles' sifting, and Jesus did not necessarily have a right to have his petition answered, at least not in the same way.

So it is a mercy for God to restore us after we have failed, not his duty.

Bible Search Algorithm part 1

I was searching for a bible search algorithm a while ago, and I couldn't find one publicly posted, so I wrote my own. Those familiar with the bible know that it is expressed in this format:
  • Book Chapter:Verse
  • e.g., John 3:16
But of course one can also show multiple references together using a combination of dashes, semi-colons, and commas.
  • John 4; James 1:2-8
    (Entire chapter 4 of John, James 1 verses 2 through 8)
  • John 7:40-8:11
    (John chapter 7 verse 40 through chapter 8 verse 11)
  • Ge 12:1-8; 15:1-6
    (Genesis chapter 12 verse 1 through 8, chapter 15 verse 1 through 6)
So I was considering how I could parse this down. I wrote to a few sites who do search results according to these generally agreed-upon principles, but I got no reply. So I wrote my own and thought I would share it. It's written in PHP but could certainly be adapted to anything. It does not use OOP and could probably be improved upon, but I am not a programmer by nature, so I figured I would just post what I have.

There are a few functions that work together to do the job. I will post the first one here with an explanation. This function normalizes the input into something that the other functions can use.


This function is designed to be called with the raw input. Here is what it would show for the various inputs above:

  • Array
    (
        [0] => John 4
        [1] => James 1:2-8
    )
  • Array
    (
        [0] => John 7:40-8:11
    )
  • Array
    (
        [0] => Ge 12:1-8
        [1] => Ge  15:1-6
    )

In the next post I'll talk about the next step in processing the data, which is breaking out the ranges into a top-most range and a bottom-most range using the hyphens as guidelines.

In subsequent posts, I'll outline the procedure for converting the abbreviation into the full book name (e.g., Ge → Genesis) and actually pulling data from the database, which may look different for different people depending on the database in use, etc.

Reading and remembering

As I was reading scripture today, I came upon Matthew 8, particularly the section that describes what one has to be willing to surrender to follow Jesus. I have read this dozens of times, but I had to "cheat" using Bible Gateway to remember where it was in scripture.

Something that I know already, but want to try more today, is sharing something you read and remember with other people. That is the best way to learn anything, not just where something is in scripture. I'm learning a new language right now, and it's well-known that the way to retain what you learn in a day is to repeat it and interact with it among lots of people.

May I be better at walking that out...

Previous working directory in Windows Command Prompt

Using bash in *nix has a handy feature: If you are in one directory and you switch to another one, you can use   cd -  to go back to the pr...