In this lab, we are going to use different approaches to scale volume of sound, and the algorithm’s effect on system performance. Here is some basic knowledge of digital sound: Digital sound is usually represented by a signed 16-bit integer signal sample, taken at a rate of around 44.1 or 48 thousand samples per second for one stream of samples for the left and right stereo channels. In order to change the volume of sound, we will have to scale the volume factor for each sample, the range of 0.00 to 1.00 (silence to full volume).
Here is the source code I got from professor: (vol1.h)
-------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "vol.h"
// Function to scale a sound sample using a volume_factor
// in the range of 0.00 to 1.00.
static inline int16_t scale_sample(int16_t sample, float volume_factor) {
return (int16_t) (volume_factor * (float) sample);
}
int main() {
// Allocate memory for large in and out arrays
int16_t* in;
int16_t* out;
in = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
out = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
int x;
int ttl;
// Seed the pseudo-random number generator
srand(-1);
// Fill the array with random data
for (x = 0; x < SAMPLES; x++) {
in[x] = (rand()%65536)-32768;
}
// ######################################
// This is the interesting part!
// Scale the volume of all of the samples
for (x = 0; x < SAMPLES; x++) {
out[x] = scale_sample(in[x], 0.75);
}
// ######################################
// Sum up the data
for (x = 0; x < SAMPLES; x++) {
ttl = (ttl+out[x])%1000;
}
// Print the sum
printf("Result: %d\n", ttl);
return 0;
}
-------------------------------------------------
And 500,000 random "sound samples" stored in (vol.h)
When I build and test the file, I got the same output each time:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -238
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -238
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -238
-------------------------------------------------
In order to count how much time spent scaling the sound samples, I added a start function and end function during scaling function.
-------------------------------------------------
start = clock();
// ######################################
// This is the interesting part!
// Scale the volume of all of the samples
for (x = 0; x < SAMPLES; x++) {
out[x] = scale_sample(in[x], 0.75);
}
// ######################################
end = clock();
total = end - start;
-------------------------------------------------
Rebuild and re-test the file, I got the output: (without samples changed)
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -126
Time spending for scaling the sound samples: 0.000977 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -126
Time spending for scaling the sound samples: 0.000959 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -126
Time spending for scaling the sound samples: 0.000981 seconds.
-------------------------------------------------
And the output of changed the sound samples to 500000:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: 956
Time spending for scaling the sound samples: 0.010667 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: 956
Time spending for scaling the sound samples: 0.010774 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: 956
Time spending for scaling the sound samples: 0.010717 seconds.
-------------------------------------------------
Obviously, the spending time is increased but sums the output array is the same.
Next, we are going to pre-calculate a lookup table of all possible sample values multiplied by the volume factor and look up each sample in that table to get the scaled values.
Here is the source code I modefied from vol1.c:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ cat vol2.c
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "vol.h"
#include <time.h>
// Function to scale a sound sample using a volume_factor
// in the range of 0.00 to 1.00.
static inline int16_t scale_sample(int16_t sample, float volume_factor) {
return (int16_t) (volume_factor * (float) sample);
}
int main() {
// Allocate memory for large in and out arrays
int16_t* in;
int16_t* out;
int16_t* lookupTable = calloc(65536, sizeof(int16_t));
in = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
out = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
int x;
int ttl;
clock_t start, end, total;
// Seed the pseudo-random number generator
srand(-1);
// Fill the array with random data
for (x = 0; x < SAMPLES; x++) {
in[x] = (rand()%65536)-32768;
}
// Initialize lookup table by multiplied by the volume factor
for(int i=0; i<65536; i++){
lookupTable[i] = (i-32768) * 0.75;
}
start = clock();
// ######################################
// This is the interesting part!
// Scale the volume of all of the samples
for (x = 0; x < SAMPLES; x++) {
out[x] = scale_sample(in[x], 0.75);
}
// ######################################
// Sum up the data
for (x = 0; x < SAMPLES; x++) {
in[x] = (lookupTable[in[x] + 32768]);
ttl = (ttl+out[x])%1000;
}
end = clock();
total = end - start;
for(int i =0; i<10; i++){
printf("%d \n", in[i]);
}
// Print the sum
printf("Result: %d\n", ttl);
printf("Time spending for scaling the sound samples: %f seconds.\n",
(float) total/CLOCKS_PER_SEC);
return 0;
}
-------------------------------------------------
And the output is:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol2
17516
10521
8070
12072
-789
9538
1708
-15747
-20292
-15138
Result: -414
Time spending for scaling the sound samples: 0.003499 seconds.
-------------------------------------------------
The program outputs the first 10 sound samples scaled to volume from the array, and then the sum of all 500,000 scaled sound samples, and finally the time is taken for the volume-scaling part.
As we see for these versions of scaling volume of sounds, using lookup table is much faster than the original one.
Here is the source code I got from professor: (vol1.h)
-------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "vol.h"
// Function to scale a sound sample using a volume_factor
// in the range of 0.00 to 1.00.
static inline int16_t scale_sample(int16_t sample, float volume_factor) {
return (int16_t) (volume_factor * (float) sample);
}
int main() {
// Allocate memory for large in and out arrays
int16_t* in;
int16_t* out;
in = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
out = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
int x;
int ttl;
// Seed the pseudo-random number generator
srand(-1);
// Fill the array with random data
for (x = 0; x < SAMPLES; x++) {
in[x] = (rand()%65536)-32768;
}
// ######################################
// This is the interesting part!
// Scale the volume of all of the samples
for (x = 0; x < SAMPLES; x++) {
out[x] = scale_sample(in[x], 0.75);
}
// ######################################
// Sum up the data
for (x = 0; x < SAMPLES; x++) {
ttl = (ttl+out[x])%1000;
}
// Print the sum
printf("Result: %d\n", ttl);
return 0;
}
-------------------------------------------------
And 500,000 random "sound samples" stored in (vol.h)
When I build and test the file, I got the same output each time:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -238
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -238
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -238
-------------------------------------------------
In order to count how much time spent scaling the sound samples, I added a start function and end function during scaling function.
-------------------------------------------------
start = clock();
// ######################################
// This is the interesting part!
// Scale the volume of all of the samples
for (x = 0; x < SAMPLES; x++) {
out[x] = scale_sample(in[x], 0.75);
}
// ######################################
end = clock();
total = end - start;
-------------------------------------------------
Rebuild and re-test the file, I got the output: (without samples changed)
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -126
Time spending for scaling the sound samples: 0.000977 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -126
Time spending for scaling the sound samples: 0.000959 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: -126
Time spending for scaling the sound samples: 0.000981 seconds.
-------------------------------------------------
And the output of changed the sound samples to 500000:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: 956
Time spending for scaling the sound samples: 0.010667 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: 956
Time spending for scaling the sound samples: 0.010774 seconds.
[qichang@aarchie spo600_20181_vol_skel]$ ./vol1
Result: 956
Time spending for scaling the sound samples: 0.010717 seconds.
-------------------------------------------------
Obviously, the spending time is increased but sums the output array is the same.
Next, we are going to pre-calculate a lookup table of all possible sample values multiplied by the volume factor and look up each sample in that table to get the scaled values.
Here is the source code I modefied from vol1.c:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ cat vol2.c
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "vol.h"
#include <time.h>
// Function to scale a sound sample using a volume_factor
// in the range of 0.00 to 1.00.
static inline int16_t scale_sample(int16_t sample, float volume_factor) {
return (int16_t) (volume_factor * (float) sample);
}
int main() {
// Allocate memory for large in and out arrays
int16_t* in;
int16_t* out;
int16_t* lookupTable = calloc(65536, sizeof(int16_t));
in = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
out = (int16_t*) calloc(SAMPLES, sizeof(int16_t));
int x;
int ttl;
clock_t start, end, total;
// Seed the pseudo-random number generator
srand(-1);
// Fill the array with random data
for (x = 0; x < SAMPLES; x++) {
in[x] = (rand()%65536)-32768;
}
// Initialize lookup table by multiplied by the volume factor
for(int i=0; i<65536; i++){
lookupTable[i] = (i-32768) * 0.75;
}
start = clock();
// ######################################
// This is the interesting part!
// Scale the volume of all of the samples
for (x = 0; x < SAMPLES; x++) {
out[x] = scale_sample(in[x], 0.75);
}
// ######################################
// Sum up the data
for (x = 0; x < SAMPLES; x++) {
in[x] = (lookupTable[in[x] + 32768]);
ttl = (ttl+out[x])%1000;
}
end = clock();
total = end - start;
for(int i =0; i<10; i++){
printf("%d \n", in[i]);
}
// Print the sum
printf("Result: %d\n", ttl);
printf("Time spending for scaling the sound samples: %f seconds.\n",
(float) total/CLOCKS_PER_SEC);
return 0;
}
-------------------------------------------------
And the output is:
-------------------------------------------------
[qichang@aarchie spo600_20181_vol_skel]$ ./vol2
17516
10521
8070
12072
-789
9538
1708
-15747
-20292
-15138
Result: -414
Time spending for scaling the sound samples: 0.003499 seconds.
-------------------------------------------------
The program outputs the first 10 sound samples scaled to volume from the array, and then the sum of all 500,000 scaled sound samples, and finally the time is taken for the volume-scaling part.
As we see for these versions of scaling volume of sounds, using lookup table is much faster than the original one.
Comments
Post a Comment