[R] patch to enhance sound module for 96 kHz/24 bit sample sizes

Michael Tiemann michaeltiemann at mac.com
Mon Jul 9 01:56:01 CEST 2007


Greetings Matthias,

Thanks again for your sound module.  I did not ever manage to find the 
time to play with phase equations, but I found I needed the module for a 
new project involving bats.  I needed to do some work @ 96 kHz/24 bit 
sample size, and found the limitations of the sound package stop at 48 
kHz and 16 bit samples.  Here's a patch to bring things up to 96/24.  
Sorry I cannot test 192/24.  I am copying r-help in case others have 
more advanced equipment and an interest in testing it out.  Hope this helps!

BTW, if you are curious about the bats, you can check here: 
http://blogs.cnet.com/8301-13507_1-9738110-18.html?tag=more
I will be writing a follow-up that uses sound and seewave in the next 
few days.

[tiemann at localhost Desktop]$ diff -ru sound-orig/ sound
diff -ru sound-orig/man/bits.Rd sound/man/bits.Rd
--- sound-orig/man/bits.Rd    2006-02-20 12:50:53.000000000 -0500
+++ sound/man/bits.Rd    2007-07-08 19:36:08.000000000 -0400
@@ -12,13 +12,13 @@
 }
 \arguments{
   \item{s}{ a Sample object, or a string giving the name of a wav file. }
-  \item{value}{ the number of bits per sample, 8 or 16. }
+  \item{value}{ the number of bits per sample, 8, 16, or 24. }
 }
 \details{
 The replacement form can be used to reset the sampling quality of a 
Sample object, that is the number of bits per sample (8 or 16). Here, 
filenames are not accepted.
 }
 \value{
-  For \code{bits}, the bits parameter (number of bits per sample) of 
the Sample object, 8 or 16.
+  For \code{bits}, the bits parameter (number of bits per sample) of 
the Sample object, 8, 16, or 24.
 
   For \code{setBits}, a Sample object with the new \code{bits} parameter.
 }
Only in sound/man: bits.Rd~
diff -ru sound-orig/man/loadSample.Rd sound/man/loadSample.Rd
--- sound-orig/man/loadSample.Rd    2006-02-20 12:57:00.000000000 -0500
+++ sound/man/loadSample.Rd    2007-07-08 19:35:31.000000000 -0400
@@ -11,7 +11,8 @@
   \item{filecheck}{ logical. If FALSE, no check for existance and read 
permission of the file will be performed. }
 }
 \details{
-All kinds of wav files are supported: mono / stereo, 8 / 16 bits per 
sample, 1000 to 48000 samples/second.
+All kinds of wav files are supported: mono / stereo, 8 / 16 / 24 bits 
per sample, 1000 to 96000 samples/second,
+but no compressed formats are supported.
 }
 \value{
   the Sample object that is equivalent to the wav file.
Only in sound/man: loadSample.Rd~
diff -ru sound-orig/man/nullSample.Rd sound/man/nullSample.Rd
--- sound-orig/man/nullSample.Rd    2006-02-20 12:56:37.000000000 -0500
+++ sound/man/nullSample.Rd    2007-07-08 19:37:03.000000000 -0400
@@ -7,8 +7,8 @@
 \usage{nullSample(rate=44100, bits=16, channels=1)
 }
 \arguments{
-  \item{rate}{ the sampling rate, between 1000 and 48000. }
-  \item{bits}{ the sample quality (number of bits per sample), 8 or 16. }
+  \item{rate}{ the sampling rate, between 1000 and 96000. }
+  \item{bits}{ the sample quality (number of bits per sample), 8, 16, 
or 24. }
   \item{channels}{ 1 for mono, or 2 for stereo. }
 }
 \value{
Only in sound/man: nullSample.Rd~
diff -ru sound-orig/man/rate.Rd sound/man/rate.Rd
--- sound-orig/man/rate.Rd    2006-02-20 12:59:34.000000000 -0500
+++ sound/man/rate.Rd    2007-07-08 19:39:22.000000000 -0400
@@ -12,7 +12,7 @@
 }
 \arguments{
   \item{s}{ a Sample object, or a string giving the name of a wav file. }
-  \item{value}{ an integer between 1000 and 48000 giving the sampling 
rate. }
+  \item{value}{ an integer between 1000 and 96000 giving the sampling 
rate. }
 }
 \details{
 The replacement form can be used to reset the sampling rate. Here, 
filenames are not accepted.
@@ -26,7 +26,7 @@
 }
 \author{ Matthias Heymann }
 
-\note{ Common sampling rates are between 8000 and 44100 (CD quality). 
The sampling rate of DAT recorders is 48000. Not every rate is 
guaranteed to be supported by every wav file player.
+\note{ Common sampling rates are between 8000 and 44100 (CD quality). 
The sampling rate of DAT recorders is 48000.  DVD Audio supports rates 
up to 96000 (and perhaps 192000, though this has not been tested).  Not 
every rate is guaranteed to be supported by every wav file player.
 
 Future versions may use a different algorithm for sampling rate 
conversion to achieve a better sound quality for the returned sample.
 }
Only in sound/man: rate.Rd~
diff -ru sound-orig/man/Sample.Rd sound/man/Sample.Rd
--- sound-orig/man/Sample.Rd    2006-02-20 12:59:24.000000000 -0500
+++ sound/man/Sample.Rd    2007-07-08 19:39:52.000000000 -0400
@@ -14,7 +14,7 @@
 \arguments{
   \item{sound}{ a \code{channels(s)} x \code{sampleLength(s)} matrix or 
a vector of doubles describing the waveform(s) of the sample. }
   \item{rate}{ the sampling rate (number of samples per second). }
-  \item{bits}{ the sampling quality (the number of bits per sample), 8 
or 16. }
+  \item{bits}{ the sampling quality (the number of bits per sample), 8, 
16, or 24. }
   \item{s}{ an R object to be tested.}
   \item{argname}{ a string giving the name of the object that is 
tested. It is used for creating an error message. }
 }
Only in sound/man: Sample.Rd~
diff -ru sound-orig/man/Sine.Rd sound/man/Sine.Rd
--- sound-orig/man/Sine.Rd    2006-02-20 12:58:04.000000000 -0500
+++ sound/man/Sine.Rd    2007-07-08 19:40:16.000000000 -0400
@@ -17,8 +17,8 @@
 \arguments{
   \item{freq}{ the frequency (a double). }
   \item{dur}{ the duration in seconds (a double). }
-  \item{rate}{ the sampling rate, an integer between 1000 and 48000. }
-  \item{bits}{ the sampling quality in bits per sample, 8 or 16. }
+  \item{rate}{ the sampling rate, an integer between 1000 and 96000. }
+  \item{bits}{ the sampling quality in bits per sample, 8, 16, or 24. }
   \item{channels}{ 1 for mono, or 2 for stereo. }
   \item{reverse}{ logical. If \code{TRUE}, the waveform will be 
mirrored vertically. }
   \item{upPerc}{ a number between 0 and 100 giving the percentage of 
the waveform with value +1. }
Only in sound/man: Sine.Rd~
diff -ru sound-orig/R/sound.R sound/R/sound.R
--- sound-orig/R/sound.R    2007-04-24 08:12:47.000000000 -0400
+++ sound/R/sound.R    2007-07-08 11:13:03.000000000 -0400
@@ -71,10 +71,10 @@
 as.Sample <- function(sound,rate=44100,bits=16){
   if (mode(sound)!="numeric")
     stop("Argument 'sound' must be a numeric vectors.")
-  if (mode(rate)!="numeric" || rate<1000 || rate>48000)
-    stop("Parameter 'rate' must be an number between 1000 and 48000.")
-  if (mode(bits)!="numeric" || bits!=8 && bits!=16)
-    stop("Parameter 'bits' must be 8 or 16.")
+  if (mode(rate)!="numeric" || rate<1000 || rate>96000)
+    stop("Parameter 'rate' must be an number between 1000 and 96000.")
+  if (mode(bits)!="numeric" || bits!=8 && bits!=16 && bits!=24)
+    stop("Parameter 'bits' must be 8, 16, or 24.")
   if (is.null(dim(sound)))
     sound <- matrix(sound,nrow=1)
   if (dim(sound)[1]>2){
@@ -125,23 +125,44 @@
   if(readChar(fileR, nchars=4) != 'WAVE')
     stop("File is not WAVE format.")
 
-              readBin(fileR,"integer",n=10,size=1)
+  # "fmt " (4 bytes) + Chunk Data Size (4 bytes) + Compression Code (2 
bytes)
+              readBin(fileR,"integer",n=8,size=1)
+
+  compressionCode = readBin(fileR,"integer", size=2, endian='little')
+  if (compressionCode > 1)
+    stop ("unknown compression code.")
+
   channels <- readBin(fileR,"integer",     size=2, endian='little')
   rate     <- readBin(fileR,"integer",     size=4, endian='little')
+
+  # avg. bytes per second (4 bytes) + Block align (2 bytes)
               readBin(fileR,"integer",n= 6,size=1)
+
   bits     <- readBin(fileR,"integer",     size=2, endian='little')
-              readBin(fileR,"integer",n= 4,size=1)
+
+  # "data" (4 bytes)
+  dataMarker <- readChar(fileR, 4)
+  if (dataMarker != "data")
+    stop ("'data' marker missing.")
+
   Length   <- readBin(fileR,"integer",     size=4, endian='little')
+
+  print (Length)
+
   if (bits==8)
       data <- readBin(fileR,"integer",n=Length  ,size=1,signed=FALSE, 
endian='little')
-  else
+  else if (bits==16)
       data <- readBin(fileR,"integer",n=Length/2,size=2,signed=TRUE , 
endian='little')
+  else
+      data <- read.fwf(fileR,width=3,n=Length/3)
   close(fileR)
 
   if (bits==8)
     data   <- data/128-1
-  else
+  else if (bits==16)
     data   <- data/32768
+  else
+    data   <- data/16777216
 
   if (channels==2)
     dim(data) <- c(channels,length(data)/channels)
@@ -166,7 +187,8 @@
     else  {data <- array(sound(s),dim=c(1,2*sampleLength(s)))}
 
   if (bits(s)==8) data <- data*127+128
-  else data <- data*32767
+  else if (bits(s)==16) data <- data*32767
+  else data <- data*16777216
 
   dataLength <- length(data)*bits(s)/8
 
@@ -182,7 +204,7 @@
   writeBin(as.integer(channels(s)),fileA,size=2, 
endian='little')             # 1=mono / 2=stereo
   writeBin(as.integer(rate(s)),fileA, 
endian='little')                        # sample rate
   writeBin(as.integer(rate(s)*channels(s)*bits(s)/8),fileA, 
endian='little')  # bytes/second
-  writeBin(as.integer(channels(s)*bits(s)/8),fileA,size=2, 
endian='little')   # bytes/sample
+  writeBin(as.integer(channels(s)*bits(s)/8),fileA,size=bits(s)/8, 
endian='little')   # bytes/sample
   writeBin(as.integer(bits(s)),fileA,size=2, 
endian='little')                 # bits/sample
 
   
writeChar("data",fileA,eos=NULL)                                            
# "data"
@@ -366,8 +388,8 @@
 "bits<-" <- function(s,value){
   if (is.null(class(s)) || class(s)!="Sample")
     stop("Argument 's' must be of class 'Sample'.")
-  if (mode(value)!="numeric" || (value!=8 && value!=16))
-    stop("Number of bits must be 8 or 16.")
+  if (mode(value)!="numeric" || (value!=8 && value!=16 && value!=24))
+    stop("Number of bits must be 8, 16, or 24.")
   else s$bits <- value
   return(s)
 }
@@ -375,8 +397,8 @@
 "rate<-" <- function(s,value){
   if (is.null(class(s)) || class(s)!="Sample")
     stop("Argument 's' must be of class 'Sample'.")
-  if (mode(value)!="numeric" || value<1000 || value>48000)
-    stop("Rate must be an number between 1000 and 48000.")
+  if (mode(value)!="numeric" || value<1000 || value>96000)
+    stop("Rate must be an number between 1000 and 96000.")
   if (rate(s)==value) return(s)
   ch <- channels(s)
   sound(s) <- 
sound(s)[,as.integer(seq(1,sampleLength(s)+.9999,by=rate(s)/value))]
@@ -433,8 +455,8 @@
 setBits <- function(s,value){
   sampletest <- is.Sample(s)
   if (!sampletest$test) stop(sampletest$error)
-  if (mode(value)!="numeric" || (value!=8 && value!=16))
-    stop("Number of bits must be 8 or 16.")
+  if (mode(value)!="numeric" || (value!=8 && value!=16 && value!=24))
+    stop("Number of bits must be 8, 16, or 24.")
   if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
   bits(s) <- value
   return(s)
@@ -443,8 +465,8 @@
 setRate <- function(s,value){
   sampletest <- is.Sample(s)
   if (!sampletest$test) stop(sampletest$error)
-  if (mode(value)!="numeric" || value<1000 || value>48000)
-    stop("Rate must be a number between 1000 and 48000.")
+  if (mode(value)!="numeric" || value<1000 || value>96000)
+    stop("Rate must be a number between 1000 and 96000.")
   if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
   rate(s) <- value
   return(s)
Only in sound/R: sound.R~
[tiemann at localhost Desktop]$

I did this for a personal project I'm doing for fun.  Let me know 
whether you need a more formal copyright disclaimer than "I hereby offer 
this patch to be included in any software licensed under the GNU General 
Public Lincese (version 2 or later)".

Michael Tiemann



More information about the R-help mailing list