Saturday, January 14, 2023

Software Engineering with ChatGPT


Generated by DALL-E 2


Like many others, I am impressed by ChatGPT's ability to understand and respond to my queries. I am looking forward to trying it out for my software engineering projects and see how it can benefit my work.

As an experiment; I decided to use ChatGPT to create a command line MP3 audio recorder on Linux in C++, expecting it to be a difficult task for a language model. However, I was impressed by the tool's ability to understand the requirements and deliver efficient and well-structured code.

I began by creating a main.cpp file and adding an empty int main(...) function. To create an audio recorder, I will need to include:

  • A function to capture audio from the microphone in a specified audio format
  • A function or class with a method to convert and save audio frames as an mp3 file.

I added the following query into ChatGPT:

Write a function to capture microphone audio on Linux. The function needs to have a callback void audiodata(int16_t* data, int samples). The audio is PCM one channel 48KHz, int16_t.

And promptly it wrote the function asked for, this is part of the answer, the generated source code is below. 

Here is an example of a function in C++ that captures microphone audio on Linux and calls the callback function "audiodata" with a pointer to the int16_t data and number of samples:

I pasted the generated C++ code into my main.cpp file, but encountered a couple of errors during compilation and linking. The errors were minor and I was able to fix them quickly, such as changing an int parameter to a pointer. Additionally, I was able to quickly resolve a linker error by pasting the error message into ChatGPT, which provided the solution.

I side tracked a bit here and asked for a function to hexdump and a class to write raw data, all went just fine.

The next query was the following:

Write a linux class in c++ to convert several buffers of binary PCM, int16_t, mono data to a MP3 file. The class needs an open, write and close method.

The result was again spot on.

Here is an example of a C++ class that can be used to convert multiple buffers of binary PCM, int16_t, mono data to an MP3 file using the LAME library on Linux:


After adding the latest C++ code generated by ChatGPT to my main.cpp file, I noticed one mistake. Specifically, the method for writing buffers divided the samples by 2, which was unnecessary. I was able to easily fix this by removing the division at two locations in the code. Additionally, I did not have the LAME library installed on my system, but a few queries to ChatGPT provided me with the commands to install it and the necessary options to specify to the linker.


In conclusion, ChatGPT performed exceptionally well in my project to create a command line MP3 audio recorder on Linux in C++. Its ability to understand the requirements and produce efficient and well-structured code was impressive. If this trend continues, ChatGPT has the potential to greatly benefit the software engineering field, as well as other areas. By the way; the majority of this text was also written or rewritten by ChatGPT.


source code:


g++ chatgpt.cpp -o chatgpt_audio -lasound -lmp3lame

download code here...


#include "alsa/asoundlib.h"


snd_pcm_t *handle;
snd_pcm_hw_params_t *params;

void hexdump(void* data, size_t len) {
    unsigned char *p = (unsigned char*)data;
    for (size_t i = 0; i < len; i++) {
        printf("%02x ", p[i]);
        if ((i + 1) % 16 == 0) printf("\n");
    }
    printf("\n");
}

#include "fstream"
#include "lame/lame.h"

class MP3Encoder {
public:
    MP3Encoder(const std::string& fileName) : fileName(fileName) {
        lame = lame_init();
        lame_set_in_samplerate(lame, 48000);
        lame_set_num_channels(lame, 1);
        lame_set_out_samplerate(lame, 48000);
        lame_set_brate(lame, 128);
        lame_init_params(lame);
    }

    bool open() {
        file.open(fileName, std::ios::out | std::ios::binary);
        return file.is_open();
    }

    bool write(int16_t* data, size_t len) {
        if (!file.is_open()) return false;
        size_t bufferSize = len ;
        unsigned char buffer[bufferSize];
        int encodedSize = lame_encode_buffer(lame, (short int*)data, (short int*)data, len, buffer, bufferSize);
        file.write((char*)buffer, encodedSize);
        return true;
    }

    void close() {
        if (file.is_open()) {
            size_t bufferSize = 7200;
            unsigned char buffer[bufferSize];
            int encodedSize = lame_encode_flush(lame, buffer, bufferSize);
            file.write((char*)buffer, encodedSize);
            file.close();
        }
        lame_close(lame);
    }

private:
    std::string fileName;
    std::ofstream file;
    lame_global_flags* lame;
};
MP3Encoder *mp3;

class BinaryFileWriter {
public:
    BinaryFileWriter(const std::string& fileName) : fileName(fileName) {}

    bool open() {
        file.open(fileName, std::ios::out | std::ios::binary);
        return file.is_open();
    }

    bool write(void* data, size_t len) {
        if (!file.is_open()) return false;
        file.write((char*)data, len);
        return true;
    }

    void close() {
        if (file.is_open()) file.close();
    }

private:
    std::string fileName;
    std::ofstream file;
};

BinaryFileWriter *writer;

void audiodata(int16_t* data, int samples) {
    // do something with the audio data
    hexdump((void*)data, 20);
    writer->write((char*)data, samples * 2);
    mp3->write(data, samples);
}



void audio_capture() {
    int rc;
    int size;
    int dir;
    snd_pcm_uframes_t frames;
    int16_t buffer[48000];

    rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
    if (rc < 0) {
        // handle error
    }

    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(handle, params);
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(handle, params, 1);
    unsigned int samplerate = 48000;
    snd_pcm_hw_params_set_rate_near(handle, params, &samplerate, &dir);

    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) {
        // handle error
    }

    snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    size = frames * 2; /* 2 bytes/sample, 1 channel */

    while (1) {
        rc = snd_pcm_readi(handle, buffer, frames);
        if (rc == -EPIPE) {
            // handle overrun
        } else if (rc < 0) {
            // handle error
        } else if (rc != (int)frames) {
            // handle short read
        }
        audiodata(buffer, rc);
    }

    snd_pcm_drain(handle);
    snd_pcm_close(handle);
}


int main(int argc, char *argv[]) {
    mp3 = new MP3Encoder("/tmp/audio.mp3");
    writer = new BinaryFileWriter("/tmp/audio.i16.48.1.pcm");
    writer->open();
    mp3->open();
    audio_capture();
    writer->close();
    mp3->close();
    delete(writer);
}