Add blocksize alteration to maps
1 files changed, 157 insertions(+), 74 deletions(-)

M stream-map-fn.sml
M stream-map-fn.sml +157 -74
@@ 227,15 227,19 @@ end
 
 (**
  * Map a block stream into a new block stream using a function that
- * processes a single block. The resulting block stream will have all
- * the same metadata attributes (channels, blocksize etc) as the
- * original, so the map function must preserve the size of the matrix
- * it is supplied.
+ * processes a single block.
+ *
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
  *)
 functor BlockStreamMapFn (S : BLOCK_STREAM) :
         sig
             include BLOCK_STREAM
-            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix
+            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix,
+                         newBlocksize : int option
                        } * S.stream -> stream
         end
 = struct

          
@@ 244,22 248,29 @@ functor BlockStreamMapFn (S : BLOCK_STRE
                                  
     type stream = {
         f : SampleMatrix.matrix -> SampleMatrix.matrix,
+        newBlocksize : int option,
         upstream : S.stream
     }
 
-    type new_args = { f : SampleMatrix.matrix -> SampleMatrix.matrix }
-                    * S.new_args
+    type new_args = { f : SampleMatrix.matrix -> SampleMatrix.matrix,
+                      newBlocksize : int option
+                    } * S.new_args
 
     fun rate ({ upstream, ... } : stream) = S.rate upstream
     fun channels ({ upstream, ... } : stream) = S.channels upstream
-    fun blocksize ({ upstream, ... } : stream) = S.blocksize upstream
+
+    fun blocksize ({ newBlocksize, upstream, ... } : stream) =
+        case newBlocksize of NONE => S.blocksize upstream
+                           | SOME bs => bs
+
     fun time ({ upstream, ... } : stream) = S.time upstream
     fun seekable ({ upstream, ... } : stream) = S.seekable upstream
 
-    fun read ({ f, upstream } : stream) =
+    fun read ({ f, newBlocksize, upstream } : stream) =
         Option.map
             (fn (upstream', m) =>
                 ({ f = f,
+                   newBlocksize = newBlocksize,
                    upstream = upstream'
                  },
                  f m))

          
@@ 267,18 278,21 @@ functor BlockStreamMapFn (S : BLOCK_STRE
                     
     fun foldl f = BlockStreamFolder.makeFoldl (read, f)
    
-    fun seek ({ f, upstream } : stream, mode, t) =
+    fun seek ({ f, newBlocksize, upstream } : stream, mode, t) =
         Option.map
             (fn upstream' => { f = f,
+                               newBlocksize = newBlocksize,
                                upstream = upstream'
                              }
             )
             (S.seek (upstream, mode, t))
                 
-    fun wrap ({ f : SampleMatrix.matrix -> SampleMatrix.matrix
+    fun wrap ({ f : SampleMatrix.matrix -> SampleMatrix.matrix,
+                newBlocksize : int option
               },
               upstream) : stream = {
         f = f,
+        newBlocksize = newBlocksize,
         upstream = upstream
     }
 

          
@@ 289,11 303,14 @@ end
 (**
  * Map a pair of block streams into a single new block stream using a
  * function that produces a single new block given a single block from
- * both inputs. The two input streams consist of a main and an
- * auxiliary - the resulting block stream will have all the same
- * metadata attributes (channels, blocksize etc) as the main input
- * stream, so the map function must preserve the size of the first
- * matrix it is supplied.
+ * both inputs.
+ *
+ * The two input streams consist of a main and an auxiliary. The
+ * resulting block stream will have the same number of channels as the
+ * main input stream. If newBlocksize is specified, it will have that
+ * channel count; otherwise it will have the same number of channels
+ * as the main input stream. The map function must return the correct
+ * matrix size for the channels and blocksize.
  *)
 functor BlockStreamPairMapFn (ARG : sig
                                   structure S : BLOCK_STREAM

          
@@ 303,7 320,8 @@ functor BlockStreamPairMapFn (ARG : sig
             include BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.matrix ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct

          
@@ 315,27 333,34 @@ functor BlockStreamPairMapFn (ARG : sig
                                  
     type stream = {
         f : SampleMatrix.matrix * T.SampleMatrix.matrix -> SampleMatrix.matrix,
+        newBlocksize : int option,
         upstream : S.stream,
         aux : T.stream
     }
 
     type new_args = { f : SampleMatrix.matrix * T.SampleMatrix.matrix ->
                           SampleMatrix.matrix,
+                      newBlocksize : int option,
                       aux : T.stream
                     } * S.new_args
 
     fun rate ({ upstream, ... } : stream) = S.rate upstream
     fun channels ({ upstream, ... } : stream) = S.channels upstream
-    fun blocksize ({ upstream, ... } : stream) = S.blocksize upstream
+
+    fun blocksize ({ newBlocksize, upstream, ... } : stream) =
+        case newBlocksize of NONE => S.blocksize upstream
+                           | SOME bs => bs
+
     fun time ({ upstream, ... } : stream) = S.time upstream
     fun seekable ({ upstream, aux, ... } : stream) = 
         SampleStreamTypes.mergeSeekables [S.seekable upstream,
                                           T.seekable aux]
 
-    fun read ({ f, upstream, aux } : stream) =
+    fun read ({ f, newBlocksize, upstream, aux } : stream) =
         case (S.read upstream, T.read aux) of
             (SOME (upstream', m1), SOME (aux', m2)) =>
             SOME ({ f = f,
+                    newBlocksize = newBlocksize,
                     upstream = upstream',
                     aux = aux'
                   },

          
@@ 344,18 369,20 @@ functor BlockStreamPairMapFn (ARG : sig
                     
     fun foldl f = BlockStreamFolder.makeFoldl (read, f)
                
-    fun seek ({ f, upstream, aux } : stream, mode, t) =
+    fun seek ({ f, newBlocksize, upstream, aux } : stream, mode, t) =
         case (S.seek (upstream, mode, t), T.seek (aux, mode, t)) of
             (SOME upstream', SOME aux') => SOME { f = f,
+                                                  newBlocksize = newBlocksize,
                                                   upstream = upstream',
                                                   aux = aux'
                                                 }
           | _ => NONE
  
-    fun wrap ({ f, aux }, upstream) =
+    fun wrap ({ f, newBlocksize, aux }, upstream) =
         if S.channels upstream <> T.channels aux
         then raise Fail "BlockStreamPairMapFn: streams must have matching channel counts"
         else { f = f,
+               newBlocksize = newBlocksize,
                upstream = upstream,
                aux = aux
              }

          
@@ 370,10 397,11 @@ end
  * block from the block stream and a single frame from the sample
  * stream.
  *
- * The resulting block stream will have all the same metadata
- * attributes (channels, blocksize etc) as the input block stream, so
- * the map function must preserve the size of the matrix it is
- * supplied.
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
  *)
 functor BlockAndSampleStreamPairMapFn (ARG : sig
                                            structure S : BLOCK_STREAM

          
@@ 383,7 411,8 @@ functor BlockAndSampleStreamPairMapFn (A
             include BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.vector ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct

          
@@ 395,27 424,34 @@ functor BlockAndSampleStreamPairMapFn (A
                                  
     type stream = {
         f : SampleMatrix.matrix * T.SampleMatrix.vector -> SampleMatrix.matrix,
+        newBlocksize : int option,
         upstream : S.stream,
         aux : T.stream
     }
 
     type new_args = { f : SampleMatrix.matrix * T.SampleMatrix.vector ->
                           SampleMatrix.matrix,
+                      newBlocksize : int option,
                       aux : T.stream
                     } * S.new_args
 
     fun rate ({ upstream, ... } : stream) = S.rate upstream
     fun channels ({ upstream, ... } : stream) = S.channels upstream
-    fun blocksize ({ upstream, ... } : stream) = S.blocksize upstream
+
+    fun blocksize ({ newBlocksize, upstream, ... } : stream) =
+        case newBlocksize of NONE => S.blocksize upstream
+                           | SOME bs => bs
+
     fun time ({ upstream, ... } : stream) = S.time upstream
     fun seekable ({ upstream, aux, ... } : stream) = 
         SampleStreamTypes.mergeSeekables [S.seekable upstream,
                                           T.seekable aux]
 
-    fun read ({ f, upstream, aux } : stream) =
+    fun read ({ f, newBlocksize, upstream, aux } : stream) =
         case (S.read upstream, T.readOne aux) of
             (SOME (upstream', m), SOME (aux', v)) =>
             SOME ({ f = f,
+                    newBlocksize = newBlocksize,
                     upstream = upstream',
                     aux = aux'
                   },

          
@@ 424,18 460,20 @@ functor BlockAndSampleStreamPairMapFn (A
                     
     fun foldl f = BlockStreamFolder.makeFoldl (read, f)
                
-    fun seek ({ f, upstream, aux } : stream, mode, t) =
+    fun seek ({ f, newBlocksize, upstream, aux } : stream, mode, t) =
         case (S.seek (upstream, mode, t), T.seek (aux, mode, t)) of
             (SOME upstream', SOME aux') => SOME { f = f,
+                                                  newBlocksize = newBlocksize,
                                                   upstream = upstream',
                                                   aux = aux'
                                                 }
           | _ => NONE
  
-    fun wrap ({ f, aux }, upstream) =
+    fun wrap ({ f, newBlocksize, aux }, upstream) =
         if S.channels upstream <> T.channels aux
         then raise Fail "BlockAndSampleStreamPairMapFn: streams must have matching channel counts"
         else { f = f,
+               newBlocksize = newBlocksize,
                upstream = upstream,
                aux = aux
              }

          
@@ 446,16 484,22 @@ end
 
 (**
  * Map a frequency-domain block stream into a new frequency-domain
- * block stream using a function that processes a single block. The
- * resulting block stream will have all the same metadata attributes
- * (channels, blocksize, frequency-domain conversion attributes etc)
- * as the original, so the map function must preserve the size of the
- * matrix it is supplied.
+ * block stream using a function that processes a single block.
+ *
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *)
 functor FrequencyDomainBlockStreamMapFn (S : FREQUENCY_DOMAIN_BLOCK_STREAM) :
         sig
             include FREQUENCY_DOMAIN_BLOCK_STREAM
-            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix
+            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix,
+                         newBlocksize : int option
                        } * S.stream -> stream
         end
 = struct

          
@@ 477,11 521,15 @@ end
  * block stream using a function that produces a single new block
  * given a single block from both inputs.
  *
- * The two input streams consist of a main and an auxiliary - the
- * resulting block stream will have all the same metadata attributes
- * (channels, blocksize, frequency-domain conversion attributes etc)
- * as the main input stream, so the map function must preserve the
- * size of the first matrix it is supplied.
+ * The two input streams consist of a main and an auxiliary. The
+ * resulting block stream will have the same number of channels as the
+ * main input stream. If newBlocksize is specified, it will have that
+ * channel count; otherwise it will have the same number of channels
+ * as the main input stream. The map function must return the correct
+ * matrix size for the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *
  * Because the metadata functions of the auxiliary stream are unused,
  * it may be any type of block stream.

          
@@ 494,7 542,8 @@ functor FrequencyDomainBlockStreamPairMa
             include FREQUENCY_DOMAIN_BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.matrix ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct

          
@@ 520,10 569,14 @@ end
  * block given a block from the block stream and a single frame from
  * the sample stream.
  *
- * The resulting block stream will have all the same metadata
- * attributes (channels, blocksize, frequency-domain conversion
- * attributes etc) as the input block stream, so the map function must
- * preserve the size of the matrix it is supplied.
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *)
 functor FrequencyDomainBlockAndSampleStreamPairMapFn (ARG : sig
                                                  structure S : FREQUENCY_DOMAIN_BLOCK_STREAM

          
@@ 533,7 586,8 @@ functor FrequencyDomainBlockAndSampleStr
             include FREQUENCY_DOMAIN_BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.vector ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct

          
@@ 556,15 610,22 @@ end
 (**
  * Map a frequency-domain polar block stream into a new
  * frequency-domain polar block stream using a function that processes
- * a single block. The resulting block stream will have all the same
- * metadata attributes (channels, blocksize, frequency-domain
- * conversion attributes etc) as the original, so the map function
- * must preserve the size of the matrix it is supplied.
+ * a single block.
+ *
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *)
 functor FrequencyDomainPolarBlockStreamMapFn (S : FREQUENCY_DOMAIN_POLAR_BLOCK_STREAM) :
         sig
             include FREQUENCY_DOMAIN_POLAR_BLOCK_STREAM
-            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix
+            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix,
+                         newBlocksize : int option
                        } * S.stream -> stream
         end
 = struct

          
@@ 586,11 647,15 @@ end
  * frequency-domain polar block stream using a function that produces
  * a single new block given a single block from both inputs.
  *
- * The two input streams consist of a main and an auxiliary -
- * the resulting block stream will have all the same metadata
- * attributes (channels, blocksize, frequency-domain conversion
- * attributes etc) as the main input stream, so the map function must
- * preserve the size of the first matrix it is supplied.
+ * The two input streams consist of a main and an auxiliary. The
+ * resulting block stream will have the same number of channels as the
+ * main input stream. If newBlocksize is specified, it will have that
+ * channel count; otherwise it will have the same number of channels
+ * as the main input stream. The map function must return the correct
+ * matrix size for the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *
  * Because the metadata functions of the auxiliary stream are unused,
  * it may be any type of block stream.

          
@@ 603,7 668,8 @@ functor FrequencyDomainPolarBlockStreamP
             include FREQUENCY_DOMAIN_POLAR_BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.matrix ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct

          
@@ 629,10 695,14 @@ end
  * single new block given a block from the block stream and a single
  * frame from the sample stream.
  *
- * The resulting block stream will have all the same metadata
- * attributes (channels, blocksize, frequency-domain conversion
- * attributes etc) as the input block stream, so the map function must
- * preserve the size of the matrix it is supplied.
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *)
 functor FrequencyDomainPolarBlockAndSampleStreamPairMapFn (ARG : sig
                                                                structure S : FREQUENCY_DOMAIN_POLAR_BLOCK_STREAM

          
@@ 642,7 712,8 @@ functor FrequencyDomainPolarBlockAndSamp
             include FREQUENCY_DOMAIN_POLAR_BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.vector ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct

          
@@ 665,15 736,22 @@ end
 (**
  * Map a frequency-domain magnitude-only block stream into a new
  * frequency-domain magnitude-only block stream using a function that
- * processes a single block. The resulting block stream will have all
- * the same metadata attributes (channels, blocksize, frequency-domain
- * conversion attributes etc) as the original, so the map function
- * must preserve the size of the matrix it is supplied.
+ * processes a single block.
+ *
+ * The resulting block stream will have the same number of channels as
+ * the original. If newBlocksize is specified, it will have that
+ * blocksize; otherwise it will have the same blocksize as the
+ * original. The map function must return the correct matrix size for
+ * the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *)
 functor FrequencyDomainMagnitudeBlockStreamMapFn (S : FREQUENCY_DOMAIN_MAGNITUDE_BLOCK_STREAM) :
         sig
             include FREQUENCY_DOMAIN_MAGNITUDE_BLOCK_STREAM
-            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix
+            val wrap : { f : S.SampleMatrix.matrix -> S.SampleMatrix.matrix,
+                         newBlocksize : int option
                        } * S.stream -> stream
         end
 = struct

          
@@ 695,11 773,15 @@ end
  * frequency-domain magnitude-only block stream using a function that
  * produces a single new block given a single block from both inputs.
  *
- * The two input streams consist of a main and an auxiliary -
- * the resulting block stream will have all the same metadata
- * attributes (channels, blocksize, frequency-domain conversion
- * attributes etc) as the main input stream, so the map function must
- * preserve the size of the first matrix it is supplied.
+ * The two input streams consist of a main and an auxiliary. The
+ * resulting block stream will have the same number of channels as the
+ * main input stream. If newBlocksize is specified, it will have that
+ * channel count; otherwise it will have the same number of channels
+ * as the main input stream. The map function must return the correct
+ * matrix size for the channels and blocksize.
+ *
+ * The resulting block stream will have the same frequency-domain
+ * conversion attributes as the input block stream.
  *
  * Because the metadata functions of the auxiliary stream are unused,
  * it may be any type of block stream.

          
@@ 712,7 794,8 @@ functor FrequencyDomainMagnitudeBlockStr
             include FREQUENCY_DOMAIN_MAGNITUDE_BLOCK_STREAM
             val wrap : { f : ARG.S.SampleMatrix.matrix * ARG.T.SampleMatrix.matrix ->
                              ARG.S.SampleMatrix.matrix,
-                         aux : ARG.T.stream
+                         aux : ARG.T.stream,
+                         newBlocksize : int option
                        } * ARG.S.stream -> stream
         end
 = struct