This assignment requires familiarity with the lecture materials presented in class through week 08.
Review the discussion in lecture regarding PCM (pulse-code modulation) and its use in representing digital audio.
You shall write a C++ program that accepts two command-line arguments specifying the width and height of an image and interprets the contents of standard input as a stream of raw (binary) 16-bit integer PCM audio samples (such as those emitted by week 08's pcm_generator
example) and emits on standard output a sequence of 8-bit grayscale pixel values representing a width×height-pixel image (similar to week 08's grayscale_pixels
example) on which the PCM waveform has been plotted as white pixels against a black background.
Assume any amount of input samples on stdin in native byte order1), and make sure that the image consists of a plot of the entire audio waveform:
double
precision.Ensure that the waveform is visible by drawing a “bounding box” around each plotted sample, i.e. color the pixels a certain distance around the plotted sample as well as the sample itself. The distance shall be:
$$ 2 \cdot \frac{\text{image width}}{\text{total # of samples}} $$
Constrain the bounding-box distance such that it is no fewer than 2 pixels and no greater than $\frac{\text{image height}}{16}$ pixels.
Since iostream
(and C++ generally) uses char
arrays to represent raw binary data (a char
is always 1 byte), you will need to read and write char
arrays. To interpret the input as 16-bit signed integer PCM samples, you can simply reinterpret a char
array as an array of signed 16-bit integers:
[cling]$ #include <cstdint> [cling]$ char raw_bytes[] = {'\xff', '\x7f', '\x01', '\x00'}; [cling]$ int16_t *samples = reinterpret_cast<int16_t *>(raw_bytes); [cling]$ samples[0] (short) 32767 [cling]$ samples[1] (short) 1
Since you will be calling read()
on std::cin
, you may find function std::istream::gcount()
useful, since it will tell you how many bytes were actually extracted:
[cling]$ char buf[1024]; [cling]$ std::cin.read(buf, 1024); Hello! [cling]$ std::cin.gcount() (long) 7
Sample executable cs19_pcm_waveform
demonstrates the expected behavior of your program, and executable cs19_pcm_generator
is a slightly fancier and configurable version of week 08's pcm_generator
example (though by default it behaves the same). You can combine these with the convert
command to generate actual image files. pcm_waveform
also prints to stderr the total number of samples received and the resulting size of the bounding box, for testing purposes (you don't have to include this in your program).
cs19_pcm_generator
accepts two optional command-line arguments:
sine
(the default if unspecified), square
, triangle
or sawtooth
(see image on the right)For example, the following command will generate a 1 second of a 4 Hz sine wave, so if we graph it we should see pretty much exactly 4 wave periods spread across the entire image:
cs19_pcm_generator <<< '4 1' | cs19_pcm_waveform 8192 512 | convert -depth 8 -size 8192x512 gray:- ~/public_html/as08.png
If you run the above command, you should see the following image at URL jeff.cis.cabrillo.edu/~/as08.png
:
Here are some other commands and their expected images:
cs19_pcm_generator <<< '20 .1 200 .1 400 .1' | cs19_pcm_waveform 17280 1080 | convert -depth 8 -size 17280x1080 gray:- ~/public_html/as08.png
cs19_pcm_generator <<< '440 .02' | cs19_pcm_waveform 800 800 | convert -depth 8 -size 800x800 gray:- ~/public_html/as08.png
cs19_pcm_generator 10000 sine <<< '196 .25 392.63 .25 261.63 .25' | cs19_pcm_waveform 8192 512 | convert -depth 8 -size 8192x512 gray:- ~/public_html/as08.png
cs19_pcm_generator 10000 square <<< '196 .25 392.63 .25 261.63 .25' | cs19_pcm_waveform 8192 512 | convert -depth 8 -size 8192x512 gray:- ~/public_html/as08.png
cs19_pcm_generator 10000 triangle <<< '196 .25 392.63 .25 261.63 .25' | cs19_pcm_waveform 8192 512 | convert -depth 8 -size 8192x512 gray:- ~/public_html/as08.png
cs19_pcm_generator 10000 sawtooth <<< '196 .25 392.63 .25 261.63 .25' | cs19_pcm_waveform 8192 512 | convert -depth 8 -size 8192x512 gray:- ~/public_html/as08.png
As submissions are received, this leaderboard will be updated with the top-performing fully/nearly functional solutions, with regard to execution speed.
Rank | Test Time (s) | Memory Usage (kB) | SLOC (lines) | User |
---|
Submit your source-code file(s) via turnin. If you submit multiple files, make sure there is only one main()
function defined.
Feedback Robot
This project has a feedback robot that will run some tests on your submission and provide you with a feedback report via email within roughly one minute.
Please read the feedback carefully.
Due at 23:59:59 on the date listed on the syllabus.
Assignment 08
is worth 60 points.
Possible point values per category: --------------------------------------- Precision of waveform 60 Possible deductions: Style and practices 10–20% Possible extra credit: Submission via Git 5% ---------------------------------------