Skip to content

MIDIStegano

stegobox.codec.MIDIStegano

Bases: BaseCodec

This algorithm write the content of the txt text document to the midi audio. MIDI-stegano is a Python program that allows you to hide some message in a MIDI file. The size of the message depends on the characteristics of the MIDI file, more precisely depends on the number of notes within the file.

  • Created by: QiuYu
  • Created time: 2022/12/05

Originally implemented in Masanar/MIDI-steganography

Source code in stegobox/codec/midi_stegano.py
class MIDIStegano(BaseCodec):
    """This algorithm write the content of the txt text
    document to the midi audio. MIDI-stegano is a Python program that allows
    you to hide some message in a MIDI file. The size of the message depends
    on the characteristics of the MIDI file, more precisely depends on the
    number of notes within the file.

    * Created by: QiuYu
    * Created time: 2022/12/05

    Originally implemented in
    [Masanar/MIDI-steganography](https://github.com/Masanar/MIDI-steganography)
    """

    def __init__(self) -> None:
        super().__init__()

    def midi_csv(self, filename):
        csv_string = filename
        count = 0
        for i in csv_string:
            line = i.strip().split(", ")
            if line[2] == "Note_on_c" or line[2] == "Note_off_c":
                count += 1
        return csv_string, count

    def csv_midi(self, csv_file):
        return csv_file

    def hide(self, csv_string, bits):
        csv_hide = []
        count = 0
        countloop = 0
        while countloop < len(csv_string):
            message = csv_string[countloop]
            new = message.strip().split(", ")
            if new[2] == "Note_on_c":
                if int(new[5]) < 10:
                    new[5] = bits[count]
                else:
                    new[5] = new[5][:-1] + bits[count]
                count += 1
            csv_hide.append((", ".join(new) + "\n"))
            countloop += 1
            if count == len(bits):
                break
        csv_hide += csv_string[countloop:]
        return csv_hide

    def encode(self, carrier: list, payload: str) -> list:
        """Encoder requires carrier audio to be MID and payload to be a txt document.

        Args:
            carrier: Carrier audio in format MID. Read with `stegobox.io.midi.read()`.
            payload: Payload (secret message) to be encoded. Payload in format TXT.
                Read with `stegobox.io.txt.read_bytes()`

        Returns:
            csv_file: Generate audio using `stegobox.io.midi.write()`.
        """
        csv, size = self.midi_csv(carrier)
        text = payload
        bits = " ".join(format(ord(x), "b") for x in text)
        lbits = len(bits.replace(" ", ""))
        while lbits >= size:
            print("\n \nThe text is too big for hide in the file")
            print("Give me the text you want to hide in the MIDI file \n")
            text = payload
            bits = " ".join(format(ord(x), "b") for x in text)
            lbits = len(bits.replace(" ", ""))
        csv_hide = self.hide(csv, bits.replace(" ", ""))

        print("\n****************The message was sucefully hide****************")
        csv_file = self.csv_midi(csv_hide)
        return csv_file
        # unhide(csv_hide)

    def decode(self, carrier: list) -> str:
        """Decode the secret payload from the carrier audio

        Args:
            carrier: Carrier audio in format MID. Read with `stegobox.io.midi.read()`.

        Returns:
            message: The decoded payload (secret message).
        """
        csv_hide, _ = self.midi_csv(carrier)
        message_bits = ""
        countloop = 0
        while countloop < len(csv_hide):
            message = csv_hide[countloop]
            new = message.strip().split(", ")
            if new[2] == "Note_on_c":
                if int(new[5]) < 10:
                    if int(new[5]) > 1:
                        break
                    else:
                        message_bits += new[5]
                else:
                    if int(new[5][-1]) > 1:
                        break
                    else:
                        message_bits += new[5][-1]
            countloop += 1
        message = self.decodebits(message_bits)
        return message[:-1]

    def decodebits(self, message_bits):
        message = ""
        for j in range(0, len(message_bits) - 1, 7):
            message += chr(int(message_bits[j : j + 7], 2))
        print("**************************************************************\n")
        print("The message hide in the .midi file is:", message)
        print("**************************************************************\n")
        return message

encode(carrier, payload)

Encoder requires carrier audio to be MID and payload to be a txt document.

Parameters:

Name Type Description Default
carrier list

Carrier audio in format MID. Read with stegobox.io.midi.read().

required
payload str

Payload (secret message) to be encoded. Payload in format TXT. Read with stegobox.io.txt.read_bytes()

required

Returns:

Name Type Description
csv_file list

Generate audio using stegobox.io.midi.write().

Source code in stegobox/codec/midi_stegano.py
def encode(self, carrier: list, payload: str) -> list:
    """Encoder requires carrier audio to be MID and payload to be a txt document.

    Args:
        carrier: Carrier audio in format MID. Read with `stegobox.io.midi.read()`.
        payload: Payload (secret message) to be encoded. Payload in format TXT.
            Read with `stegobox.io.txt.read_bytes()`

    Returns:
        csv_file: Generate audio using `stegobox.io.midi.write()`.
    """
    csv, size = self.midi_csv(carrier)
    text = payload
    bits = " ".join(format(ord(x), "b") for x in text)
    lbits = len(bits.replace(" ", ""))
    while lbits >= size:
        print("\n \nThe text is too big for hide in the file")
        print("Give me the text you want to hide in the MIDI file \n")
        text = payload
        bits = " ".join(format(ord(x), "b") for x in text)
        lbits = len(bits.replace(" ", ""))
    csv_hide = self.hide(csv, bits.replace(" ", ""))

    print("\n****************The message was sucefully hide****************")
    csv_file = self.csv_midi(csv_hide)
    return csv_file

decode(carrier)

Decode the secret payload from the carrier audio

Parameters:

Name Type Description Default
carrier list

Carrier audio in format MID. Read with stegobox.io.midi.read().

required

Returns:

Name Type Description
message str

The decoded payload (secret message).

Source code in stegobox/codec/midi_stegano.py
def decode(self, carrier: list) -> str:
    """Decode the secret payload from the carrier audio

    Args:
        carrier: Carrier audio in format MID. Read with `stegobox.io.midi.read()`.

    Returns:
        message: The decoded payload (secret message).
    """
    csv_hide, _ = self.midi_csv(carrier)
    message_bits = ""
    countloop = 0
    while countloop < len(csv_hide):
        message = csv_hide[countloop]
        new = message.strip().split(", ")
        if new[2] == "Note_on_c":
            if int(new[5]) < 10:
                if int(new[5]) > 1:
                    break
                else:
                    message_bits += new[5]
            else:
                if int(new[5][-1]) > 1:
                    break
                else:
                    message_bits += new[5][-1]
        countloop += 1
    message = self.decodebits(message_bits)
    return message[:-1]