A brief introduction to binary numbers…

Posted in Uncategorized | Tagged , , , , | Leave a comment

Can the PIC12F675 drive motors directly from its GPIO pins?

As I mentioned in my previous post, my project student Kevin Chubb is developing tiny ultra low cost robots using a PIC12F microcontroller. One of the things that’s great about PICs is that they can source and sink relatively high current through their digital i/o pins. Kevin and I have been hoping that it might be possible to build a robot that powers its actuators directly from the microcontroller pins, so that was a big factor in choosing the PIC12F. Anyway, yesterday I received a package of tiny “coreless” motors in the post from AliExpress, so I’ve just carried out an experiment to see if they can be powered directly from the GPIO pins of a PIC12F.

I received two types of motors in yesterday’s delivery, but the ones I’m using in this experiment are these ones:

To begin with, I measured the current drawn by one of the motors when it was running unloaded at 3V, which turned out to be approximately 31 mA. Although that’s slightly higher than the rated pin current on the PIC12F (25 mA), I decided it was worth taking a chance and I set up an experiment with two of the motors connected directly to a PIC12F675. Here’s the video:

The complete code is used is shown below:

//
// PIC12F675 example: motors on GP4 and GP5
// Written by Ted Burke - 20-4-2017
//
// To compile:
//
//    xc8 --chip=12F675 main.c
//
 
#include <xc.h>
 
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
 
void main(void)
{
    TRISIO = 0b11001111; // Make pins GP4 and GP5 outputs
    ANSEL  = 0b00000000; // Disable all analog inputs
     
    while(1)
    {
        GP4 = 1;         // Set pin GP4 high
        GP5 = 0;         // Set pin GP5 low
        _delay(500000);  // 0.5 second delay
        GP4 = 0;         // Set pin GP4 low
        GP5 = 1;         // Set pin GP5 high
        _delay(500000);  // 0.5 second delay
    }
}
Posted in Uncategorized | Leave a comment

Minimum Viable Program for PIC12LF1572

Kevin Chubb (currently a final-year project student here in DIT) is designing a tiny robot using Microchip’s compact PIC12LF1572 microcontroller. It’s an interesting chip and Kevin’s doing great things with it. I decided to strip back one of the example programs he sent me just to find out exactly what’s required in the code to get a minimal program (flashing LED) working. In this example, I’m just blinking an LED twice a second on pin RA5 (pin 2). Thanks for the example code Kevin!

//
// MVP (minimum viable program) for PIC12LF1572
// Written by Ted Burke based on an example by Kevin Chubb
// Last updated 13-4-2017
//

#include <xc.h>

#pragma config FOSC = INTOSC    // Select INTOSC (internal) oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF       // Disable Watchdog Timer
#pragma config MCLRE = OFF      // Disable MCLR Pin (MCLR/VPP pin function is digital input)
#pragma config LVP = OFF        // Disable Low-Voltage Programming (High-voltage on MCLR/VPP must be used for programming)

int main(void)
{
    OSCCON = 0b01111010;  // 16 Mhz oscillator (optional)
    TRISAbits.TRISA5 = 0; // Make RA5 an output
    
    while(1)
    {
        LATAbits.LATA5 = 1; // LED on
        _delay(1000000);    // 250ms @ Fosc=16MHz
        LATAbits.LATA5 = 0; // LED off
        _delay(1000000);    // 250ms @ Fosc=16MHz
    }
}

This is the circuit:

I’m using a PICkit 2 programmer in Linux, so I used the pk2cmd command line application to transfer the program to the microcontroller. Unfortunately, the standard device file (PK2DeviceFile.dat) does not include the relatively recent PIC12LF1572, so I needed to download an edited version of the file from here:

http://github.com/GBert/misc/blob/master/pickit2/pk2cmd/pk2cmd/PK2DeviceFile.dat

Once I placed the updated PK2DeviceFile.dat file into my program’s folder, pk2cmd worked perfectly. These were the commands I used to build the code and program the microcontroller:

xc8 --chip=12LF1572 main.c
sudo pk2cmd -PPIC12LF1572 -M -F main.hex -T

If the location of pk2cmd is not included in the path, you’ll probably need to specify its location in the command.

Thai Phan pointed out in one of his comments below that you don’t need to run pk2cmd as root (as I did above, using “sudo”). You can configure udev so that all users have permission to access the PICkit 2. As Thai explained it:

Create a new file /etc/udev/rules.d/99-pickit2.rules containing the following:

SUBSYSTEM==”usb”, ENV{DEVTYPE}==”usb_device”, SYSFS{idVendor}==”04d8″, SYSFS{idProduct}==”0033″, MODE=”0666″

Then restart udev, as follows:

/etc/init.d/udev restart

Unplug your PICkit 2 and then plug it back in. It should now be possible to use pk2cmd without sudo. Thanks for the useful tip Thai Phan!

Finally, Kevin had quite a few additional configuration options at the beginning of his original example program. I’ll list them here because, although they weren’t required to get my example running, some of them presumably would be required in other situations. Here they are:

// Other configuration settings from Kevin's example that I didn't use:
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config PWRTE = OFF      // Power-up Timer disable
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOREN = OFF    // Low Power Brown-out Reset enable bit (LPBOR is disabled)

Thanks again to Kevin Chubb for the example code.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , , | 6 Comments

dsPIC30F Quadrature Encoder Interface (QEI) – Basic Example

This video shows a basic example of using the Quadrature Encoder Interface (QEI) on Microchip’s dsPIC30F4011 microcontroller. I expect that the same approach will work with other microcontrollers in the dsPIC30F family.

In this example, I place two TCRT5000 reflective infrared sensors in front of a spinning black and white checkered disc to generate a pair of quadrature encoded signals. These signals are connected to pins QEA and QEB (the QEI input pins) on the dsPIC. The program shown in the example enables QEI so that the rotation of the disc is recorded in the POSCNT (position count) register. The value of POSCNT is printed via UART every 200 ms, so that it can be monitored on the PC screen.

This is the complete code:

//
// Quadrature Encoder Interface (QEI) example for dsPIC30F4011
// Written by Ted Burke, Last updated 12-4-2017
//

#include <xc.h>
#include <libpic30.h>
#include <stdio.h>
 
// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin
 
void main()
{
    // Use RD0 to blink an LED so that we can see program in running
    _TRISD0 = 0;
     
    // Setup UART so that we can monitor POSCNT value
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART
    
    // To use pins 6 and 7 as QEA and QEB (quadrature encoding inputs)
    // analog input must be disabled on both pins by setting the bits
    // for AN4 and AN5 in the ADPCFG register.
    _PCFG4 = 1;
    _PCFG5 = 1;
    
    // Enable the QEI module (x4 mode with POSCNT reset by MAXCNT match)
    _QEIM = 0b111;

    while(1)
    {
        // Print current value of position counter register
        printf("POSCNT = %d\n", POSCNT);
        
        _LATD0 = 1;         // LED on
        __delay32(3000000); // 100 ms
        _LATD0 = 0;         // LED off
        __delay32(3000000); // 100 ms
    }
}
Posted in Uncategorized | 1 Comment

Simple example program for the PIC12F675 microcontroller

The PIC12F675 is a very inexpensive 8-bit microcontroller from Microchip that’s available in an 8-pin DIP package (i.e. it’s suitable for breadboard use). I’ve had a small tube of these on the shelf for a few years, but I’ve only just got around to trying one out. In this post, I present a simple example circuit and program, which flashes an LED on one of the GPIO pins. The example circuit includes connections to the PICkit2 USB programmer that I’m using to program the device. The PICkit2 also supplies power to the circuit.

First, here’s the video of the example program running on the PIC12F675.

Example Code

This is the full C code for the flashing LED example. I built it using Microchip’s XC8 compiler (the compiler command line is shown in the opening comments).

//
// PIC12F675 example: blink an LED on pin GP5
// Written by Ted Burke - 18-2-2017
//
// To compile:
//
//    xc8 --chip=12F675 main.c
//

#include <xc.h>

#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF

void main(void)
{
    TRISIO = 0b11011111; // Make pin GP5 a digital output
    
    while(1)
    {
        GP5 = 1;         // Set pin GP5 high
        _delay(500000);  // 0.5 second delay
        GP5 = 0;         // Set pin GP5 low
        _delay(500000);  // 0.5 second delay
    }
}

Example Circuit

pic12f675_circuit

Here’s my breadboard circuit:

20170217_162941

Posted in Uncategorized | Tagged , , , , , , , , , , , | Leave a comment

A simple way to read and write audio and video files in C using FFmpeg (part 2: video)

In my previous post, I demonstrated how FFmpeg can be used to pipe raw audio samples in and out of a simple C program to or from media files such as WAV files (based on something similar for Python I found on Zulko’s blog). The same idea can be used to perform video processing, as shown in the program below.

Reading and writing a video file

In this example I use two pipes, each connected to its own instance of FFmpeg. Basically, I read frames one at time from the input pipe, invert the colour of every pixel, and then write the modified frames to the output pipe. The input video I’m using is teapot.mp4, which I recorded on my phone. The modified video is saved to a second file, output.mp4. The video resolution is 1280×720, which I checked in advance using the ffprobe utility that comes with FFmpeg.

The full code is below, but first let’s see the original and modified videos:

The original and modified MP4 video files can be downloaded here:

The program I wrote to convert the original video into the modified version is shown below.

//
// Video processing example using FFmpeg
// Written by Ted Burke - last updated 12-2-2017
//

#include <stdio.h>

// Video resolution
#define W 1280
#define H 720

// Allocate a buffer to store one frame
unsigned char frame[H][W][3] = {0};

void main()
{
    int x, y, count;
    
    // Open an input pipe from ffmpeg and an output pipe to a second instance of ffmpeg
    FILE *pipein = popen("ffmpeg -i teapot.mp4 -f image2pipe -vcodec rawvideo -pix_fmt rgb24 -", "r");
    FILE *pipeout = popen("ffmpeg -y -f rawvideo -vcodec rawvideo -pix_fmt rgb24 -s 1280x720 -r 25 -i - -f mp4 -q:v 5 -an -vcodec mpeg4 output.mp4", "w");
    
    // Process video frames
    while(1)
    {
        // Read a frame from the input pipe into the buffer
        count = fread(frame, 1, H*W*3, pipein);
        
        // If we didn't get a frame of video, we're probably at the end
        if (count != H*W*3) break;
        
        // Process this frame
        for (y=0 ; y<H ; ++y) for (x=0 ; x<W ; ++x)
        {
            // Invert each colour component in every pixel
            frame[y][x][0] = 255 - frame[y][x][0]; // red
            frame[y][x][1] = 255 - frame[y][x][1]; // green
            frame[y][x][2] = 255 - frame[y][x][2]; // blue
        }
        
        // Write this frame to the output pipe
        fwrite(frame, 1, H*W*3, pipeout);
    }
    
    // Flush and close input and output pipes
    fflush(pipein);
    pclose(pipein);
    fflush(pipeout);
    pclose(pipeout);
}

The FFmpeg options used for the input pipe are as follows.

FFmpeg option Explanation
-i teapot.mp4 Selects teapot.mp4 as the input file.
-f image2pipe Tells FFmpeg to convert the video into a sequence of frame images (I think!).
-vcodec rawvideo Tells FFmpeg to output raw video data (i.e. plain unencoded pixels).
-pix_fmt rgb24 Sets the pixel format of the raw data produced by FFmpeg to 3-bytes per pixel – one byte for red, one for blue and one for green.
- This final “-” tells FFmpeg to write to stdout, which in this case will send it into our C program via the input pipe.

The FFmpeg options used for the output pipe are as follows.

FFmpeg option Explanation
-y Tells FFmpeg to overwrite the output file if it already exists.
-f rawvideo Sets the input format as raw video data. I’m not too sure about the relationship between this option and the next one!
-vcodec rawvideo Tells FFmpeg to interpret its input as raw video data (i.e. unencoded frames of plain pixels).
-pix_fmt rgb24 Sets the input pixel format to 3-byte RGB pixels – one byte for red, one for blue and one for green.
-s 1280x720 Sets the frame size to 1280×720 pixels. FFmpeg will form the incoming pixel data into frames of this size.
-r 25 Sets the frame rate of the incoming data to 25 frames per second.
-i - Tells FFmpeg to read its input from stdin, which means it will be reading the data out C program writes to its output pipe.
-f mp4 Sets the output file format to MP4.
-q:v 5 This controls the quality of the encoded MP4 file. The numerical range for this option is from 1 (highest quality, biggest file size) to 32 (lowest quality, smallest file size). I arrived at a value of 5 by trial and error. Subjectively, it seemed to me to give roughly the best trade off between file size and quality.
-an Specifies no audio stream in the output file.
-vcodec mpeg4 Tells FFmpeg to use its “mpeg4” encoder. I didn’t try any others.
output.mp4 Specifies output.mp4 as the output file.

Epilogue: concatenating videos and images

As an interesting aside, the video I embedded above showing the original and modified teapot videos was spliced together using a slightly modified version of the example program above. Of course, it’s possible to concatenate (splice together) multiple files of different formats using ffmpeg on its own, but I couldn’t quite figure out the correct command line, so I just wrote my own little program to do it.

The files being joined together are:

The full source code is shown below.

//
// combine.c - Join multiple MP4 videos and PNG images into one video
// Written by Ted Burke - last updated 12-2-2017
//
// To compile:
// 
//    gcc combine.c
// 

#include <stdio.h>

// Video resolution
#define W 1280
#define H 720

// Allocate a buffer to store one frame
unsigned char frame[H][W][3] = {0};

void main()
{
    int count, n;
    FILE *pipein;
    FILE *pipeout;
    
    // Open output pipe
    pipeout = popen("ffmpeg -y -f rawvideo -vcodec rawvideo -pix_fmt rgb24 -s 1280x720 -r 25 -i - -f mp4 -q:v 5 -an -vcodec mpeg4 combined.mp4", "w");
    
    // Write first 50 frames using original video title image from title_original.png
    pipein = popen("ffmpeg -i title_original.png -f image2pipe -vcodec rawvideo -pix_fmt rgb24 -", "r");
    count = fread(frame, 1, H*W*3, pipein);
    for (n=0 ; n<50 ; ++n)
    {
        fwrite(frame, 1, H*W*3, pipeout);
        fflush(pipeout);
    }
    fflush(pipein);
    pclose(pipein);
    
    // Copy all frames from teapot.mp4 to output pipe
    pipein = popen("ffmpeg -i teapot.mp4 -f image2pipe -vcodec rawvideo -pix_fmt rgb24 -", "r");
    while(1)
    {
        count = fread(frame, 1, H*W*3, pipein);
        if (count != H*W*3) break;
        fwrite(frame, 1, H*W*3, pipeout);
        fflush(pipeout);
    }
    fflush(pipein);
    pclose(pipein);

    // Write next 50 frames using modified video title image from title_modified.png
    pipein = popen("ffmpeg -i title_modified.png -f image2pipe -vcodec rawvideo -pix_fmt rgb24 -", "r");
    count = fread(frame, 1, H*W*3, pipein);
    for (n=0 ; n<50 ; ++n)
    {
        fwrite(frame, 1, H*W*3, pipeout);
        fflush(pipeout);
    }
    fflush(pipein);
    pclose(pipein);
    
    // Copy all frames from output.mp4 to output pipe
    pipein = popen("ffmpeg -i output.mp4 -f image2pipe -vcodec rawvideo -pix_fmt rgb24 -", "r");
    while(1)
    {
        count = fread(frame, 1, H*W*3, pipein);
        if (count != H*W*3) break;
        fwrite(frame, 1, H*W*3, pipeout);
        fflush(pipeout);
    }
    fflush(pipein);
    pclose(pipein);
    
    // Flush and close output pipe
    fflush(pipeout);
    pclose(pipeout);
}

Note: I used Inkscape to create the video title images. Click here to download the editable Inkscape SVG file.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , , , , , , , , | Leave a comment

A simple way to read and write audio and video files in C using FFmpeg (part 1: audio)

C is my favourite programming language and the one I use most often. However, I have tended to shy away from using it for quick one-off signal processing tasks where I needed to read or write audio or video files because it always seemed like a lot of hassle figuring out which library to use and what functions to call to actually get access to the raw data. Recently though, I’ve found a new way of dealing with audio and video files that is relatively painless, so I think it’s worth sharing.

I first learned of this approach from an article on Zulko’s fascinating Python oriented blog on GitHub:

The article describes using FFmpeg to read and write video frames in Python and there’s a link to a second article showing the same thing for audio.

The basic idea is to launch FFmpeg via a pipe, which then converts raw samples to the required format (for writing) or decodes the file into raw samples (for reading). It may seem like a bit of a hack, but it’s surprisingly effective and, provided that you can figure out the correct FFmpeg command line, extremely adaptable.

FFmpeg is described on its project web page as “[a] complete, cross-platform solution to record, convert and stream audio and video.” That’s a pretty accurate description. So far, I haven’t needed to read or write any file format that it couldn’t handle, although in some cases it did involve some googling to figure out the required command line arguments.

FFmpeg is free software and cross-platform, so you should be able to install it on Windows and Mac without too much difficulty, but I haven’t actually tried that myself. I’m working on Xubuntu Linux, so to install FFmpeg I just did this:

sudo apt-get install ffmpeg

Ok, time for some practical examples…

Writing a WAV audio file (or MP3, FLAC, or whatever format you like)

The following example creates a 1-second long WAV audio file (PCM, 16-bit signed integer samples, 44.1 kHz sampling frequency). The sound is just a loud 1 kHz sine wave.

//
// writewav.c - Create a wav file by piping raw samples to ffmpeg
// Written by Ted Burke - last updated 10-2-2017
//
// To compile:
//
//    gcc writewav.c -o writewav -lm
//

#include <stdio.h>
#include <stdint.h>
#include <math.h>

#define N 44100

void main()
{
    // Create audio buffer
    int16_t buf[N] = {0}; // buffer
    int n;                // buffer index
    double Fs = 44100.0;  // sampling frequency
    
    // Generate 1 second of audio data - it's just a 1 kHz sine wave
    for (n=0 ; n<N ; ++n) buf[n] = 16383.0 * sin(n*1000.0*2.0*M_PI/Fs);
    
    // Pipe the audio data to ffmpeg, which writes it to a wav file
    FILE *pipeout;
    pipeout = popen("ffmpeg -y -f s16le -ar 44100 -ac 1 -i - beep.wav", "w");
    fwrite(buf, 2, N, pipeout);
    pclose(pipeout);
}

General comments:

  • I used the fixed length int data type int16_t for the audio buffer just to make absolutely sure I got 16-bit signed integer samples. That type is defined in the stdint.h header file. You can use a different data type, provided it matches the format your writing.
  • In the single-line for loop where I generate the sine wave, I used M_PI which is actually just the value of π (the mathematical constant). M_PI is defined in the math.h header file. Because I used M_PI, I had to link to the math library, which is why the suggested compiler command line includes the -lm option.
  • The popen() function launches a separate program which is accessible via a “pipe” using C’s standard file i/o functions. The first argument to popen is the command line for the program being launched (in this case FFmpeg). The second argument to popen specifies whether we’ll be reading data from that program through the pipe or vice versa. In this case, the second argument is "w" which means that we’ll be sending data to FFmpeg through the pipe. The return value from popen is a file descriptor for the pipe.
  • In this example, the fwrite() function is used to send the entire contents of the audio buffer into the pipe.
  • Finally, the pclose() function is used to close the pipe.

The FFmpeg command line:

The first argument to the popen() function is a string containing the full FFmpeg command line. The specified options included in that command line control how FFmpeg will interpret the raw sample data it receives through the pipe and the type of file it will write.

  • The "-y" option tells FFmpeg that it can overwrite the specified output file if it already exists.
  • The "-f s16le" option tells FFmpeg that the format of the audio data it reads (from its standard input, which means via the pipe from our program) is raw PCM, signed integer, 16-bit and little-endian.
  • The "-ar 44100" option tells FFmpeg that the sampling rate (i.e. sampling frequency) of the audio data it reads is 44.1 kHz.
  • The "-ac 1" option tells FFmpeg that the number of channels in the audio data it reads is 1.
  • The "-i -" option tells FFmpeg to read its input from standard input, which in this case means from the pipe, since FFmpeg was launched by popen.
  • Finally, beep.wav is the output filename FFmpeg will use.

If you want to hear the output file, you can download it here: beep.wav

Reading a WAV audio file (or MP3, FLAC or whatever format you like)

The following example reads 20 ms of samples from the beginning of a WAV file called whistle.wav (click it to download the file), then prints the sample values to a CSV file. The WAV file format is 16-bit signed integer samples, mono, with a sampling frequency of 44.1 kHz.

//
// readwav.c - Read samples from a WAV file using FFmpeg via a pipe
// Written by Ted Burke - last updated 10-2-2017
//
// To compile:
//
//    gcc readwav.c -o readwav -lm
//

#include <stdio.h>
#include <stdint.h>

#define N 882

void main()
{
    // Create a 20 ms audio buffer (assuming Fs = 44.1 kHz)
    int16_t buf[N] = {0}; // buffer
    int n;                // buffer index
    
    // Open WAV file with FFmpeg and read raw samples via the pipe.
    FILE *pipein;
    pipein = popen("ffmpeg -i whistle.wav -f s16le -ac 1 -", "r");
    fread(buf, 2, N, pipein);
    pclose(pipein);
    
    // Print the sample values in the buffer to a CSV file
    FILE *csvfile;
    csvfile = fopen("samples.csv", "w");
    for (n=0 ; n<N ; ++n) fprintf(csvfile, "%d\n", buf[n]);
    fclose(csvfile);
}

A screenshot of the resulting CSV file, samples.csv, open for viewing in my text editor is shown below.

samples-csv_geany_screenshot

This example program shares many elements with the previous one, but there are a couple of noteworthy differences:

  • The FFmpeg command line specified in the first argument of the popen() function tells FFmpeg to read its input from the file whistle.wav (the exact format will be detected automatically) and write its output to stdout as raw samples (16-bit signed integers, little-endian).
  • The second argument to popen is "r", which means that our program will read FFmpeg’s standard output via the pipe (it was the other way around in the previous example).

To ensure that the raw samples coming from FFmpeg are the correct size for my audio buffer, I specified "-f s16le" as a command line argument to FFmpeg. This was actually redundant in my case, because the WAV file I happened to be using was already in that format. I decided to explicitly specify the format anyway, just to show that FFmpeg can convert to a specific format if desired.

Modifying a WAV audio file

This example reads, modifies and writes a WAV audio file. It actually launches two instances of FFmpeg. One opens the original WAV file ("12345678.wav") and passes raw 16-bit signed integer samples into this program via a pipe. The other receives modified samples from this program via a second pipe and writes them to another WAV file ("out.wav"). The modification that is applied to the samples is a simple tremolo effect (modulation of the signal amplitude).

//
// modifywav.c - Modify a WAV file using FFmpeg via pipes
// This example adds a crude tremolo effect to the audio
// Written by Ted Burke - last updated 10-2-2017
//
// To compile:
//
//    gcc modifywav.c -o modifywav -lm
//

#include <stdio.h>
#include <stdint.h>
#include <math.h>

void main()
{
    // Launch two instances of FFmpeg, one to read the original WAV
    // file and another to write the modified WAV file. In each case,
    // data passes between this program and FFmpeg through a pipe.
    FILE *pipein;
    FILE *pipeout;
    pipein  = popen("ffmpeg -i 12345678.wav -f s16le -ac 1 -", "r");
    pipeout = popen("ffmpeg -y -f s16le -ar 44100 -ac 1 -i - out.wav", "w");
    
    // Read, modify and write one sample at a time
    int16_t sample;
    int count, n=0;
    while(1)
    {
        count = fread(&sample, 2, 1, pipein); // read one 2-byte sample
        if (count != 1) break;
        ++n;
        sample = sample * sin(n * 5.0 * 2*M_PI / 44100.0);
        fwrite(&sample, 2, 1, pipeout);
    }
    
    // Close input and output pipes
    pclose(pipein);    
    pclose(pipeout);
}

In case you want to hear the original and modified WAV audio files, here they are:

Click here to continue to part 2, where I show how to apply the same approach to video processing.

Posted in Uncategorized | Tagged , , , , , , , , , , , , , , , , , , , , , | 1 Comment