Sunday, January 19, 2025

Generate Music Through Python – A Complete Guide

Introduction

Music generation with Python has become more accessible with powerful libraries that allow us to compose melodies, generate MIDI files, and convert them into audio formats like WAV and MP3. This guide walks through the process of creating a MIDI file, synthesizing it into WAV using FluidSynth, and finally converting it to MP3 using pydub.

By the end of this guide, you will have a fully functional Python script that generates music and exports it as an MP3 file.


Why Use Python for Music Generation?

Python provides several libraries that make it easy to create and manipulate music:

  • MIDIUtil – Generates MIDI files programmatically.
  • Mingus – Provides music theory functions and chord generation.
  • FluidSynth – A real-time synthesizer that converts MIDI to WAV.
  • pydub – Converts audio formats, such as WAV to MP3.

Using these libraries, we can generate music from scratch and export it into an audio format that can be played on any device.


Setting Up the Environment

Before running the script, install the necessary dependencies:

Install Python Libraries

Run the following command in your terminal:

pip install midiutil mingus pyfluidsynth pydub

Install FluidSynth

  1. Download FluidSynth from the official repository:
    FluidSynth Releases
  2. Extract it to C:\tools\fluidsynth
  3. Add C:\tools\fluidsynth\bin to your system PATH (for command-line access).
  4. Verify the installation by running:
    fluidsynth --version

Download a SoundFont (.sf2) File

FluidSynth requires a SoundFont file to map MIDI notes to instrument sounds.

How Music is Generated in Python

Music generation in Python follows these key principles:

Understanding MIDI File Structure

A MIDI (Musical Instrument Digital Interface) file contains:

  • Note Data – The pitches and durations of notes.
  • Velocity – The intensity of each note.
  • Instrument Information – Which instruments to use for playback.

Unlike audio formats like MP3 or WAV, MIDI does not contain actual sound data, meaning it must be played back using a synthesizer like FluidSynth.

Breaking Down the Composition Process

  1. Chords and Progressions

    • Chords are groups of notes played together.
    • A chord progression is a sequence of chords that forms a harmonic structure for the music.
    • Example: "C → G → Am → F" is a common progression.
  2. Melody Generation

    • A melody is a sequence of individual notes that create a recognizable tune.
    • The script selects notes from a chord to create a simple melodic line.
  3. Bassline Generation

    • The bassline is usually the root note of each chord, played in a lower octave.
    • It provides rhythm and harmonic stability.
  4. MIDI to Audio Conversion

    • Since MIDI files do not contain actual sound, FluidSynth uses a SoundFont to generate audio.
    • Finally, we convert the generated WAV file to MP3 using pydub.

Python Script to Generate MIDI and Convert to MP3

This script will:

  1. Generate a MIDI file with chord progressions, a melody, and a bassline.
  2. Convert MIDI to WAV using FluidSynth and a SoundFont.
  3. Convert WAV to MP3 using pydub.

Python Script


import random import os import subprocess from midiutil import MIDIFile from mingus.core import chords from pydub import AudioSegment # Define paths SOUNDFONT_PATH =os.path.join(os.getcwd(), "FluidR3_GM.sf2") # Update your SoundFont path MIDI_FILENAME = "generated_music.mid" WAV_FILENAME = "generated_music.wav" MP3_FILENAME = "generated_music.mp3" # Define chord progressions verse = ["C", "G", "Am", "F"] chorus = ["F", "C", "G", "Am"] bridge = ["Dm", "A7", "G", "C"] song_structure = [verse, verse, chorus, verse, bridge, chorus] # MIDI settings track = 0 channel = 0 time = 0 # Start time in beats tempo = 120 # BPM volume = 100 # MIDI velocity # Create a MIDI file MyMIDI = MIDIFile(1) MyMIDI.addTempo(track, time, tempo) # Assign instruments instrument_chords = 0 # Acoustic Piano instrument_melody = 40 # Violin instrument_bass = 33 # Acoustic Bass MyMIDI.addProgramChange(track, channel, time, instrument_chords) MyMIDI.addProgramChange(track, channel + 1, time, instrument_melody) MyMIDI.addProgramChange(track, channel + 2, time, instrument_bass) # Convert note names to MIDI numbers def note_to_number(note: str, octave: int) -> int: NOTES = ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'] NOTES_IN_OCTAVE = len(NOTES) return NOTES.index(note) + (NOTES_IN_OCTAVE * octave) # Generate music for section in song_structure: for chord in section: chord_notes = chords.from_shorthand(chord) random.shuffle(chord_notes) rhythm_pattern = [0, 0.5, 1, 1.5, 2, 2.5, 3] # Add chords for i, note in enumerate(chord_notes): octave = 3 midi_note = note_to_number(note, octave) MyMIDI.addNote(track, channel, midi_note, time + rhythm_pattern[i % len(rhythm_pattern)], 1, volume) # Add bassline bass_note = note_to_number(chord_notes[0], 2) MyMIDI.addNote(track, channel + 2, bass_note, time, 4, volume) # Add melody melody_note = note_to_number(random.choice(chord_notes), 5) melody_duration = random.choice([0.5, 1, 1.5]) MyMIDI.addNote(track, channel + 1, melody_note, time + 2, melody_duration, volume) time += 4 # Save MIDI file with open(MIDI_FILENAME, "wb") as output_file: MyMIDI.writeFile(output_file) # Convert MIDI to WAV using FluidSynth subprocess.run(f'fluidsynth -ni -F {WAV_FILENAME} -r 44100 {SOUNDFONT_PATH} {MIDI_FILENAME}', shell=True, check=True) # Convert WAV to MP3 using pydub AudioSegment.from_wav(WAV_FILENAME).export(MP3_FILENAME, format="mp3")

Running the Script

Once dependencies are installed, run:

python generate_music.py

This generates:

  • generated_music.mid (MIDI file)
  • generated_music.wav (WAV file)
  • generated_music.mp3 (MP3 file)

Next Steps

  • Customize the chord progressions
  • Experiment with different instruments
  • Generate longer compositions
  • Integrate AI-generated melodies

Start generating music with Python today!

Saturday, January 18, 2025

Convert MP3 to MIDI Using Spotify’s BasicPitch and TensorFlow

Have you ever wanted to convert an MP3 file into a MIDI format for music production, transcription, or remixing?

BasicPitch by Spotify is an open-source AI-powered tool that makes this process simple and accurate.

With just a few lines of Python code, you can extract notes and melodies from an audio file and use them in a Digital Audio Workstation (DAW) or for further analysis. Let’s dive in.


What is BasicPitch?

BasicPitch is an AI-powered polyphonic pitch detection model developed by Spotify. Unlike traditional MIDI conversion tools, BasicPitch:

  • Detects multiple notes at once (polyphonic transcription)
  • Understands pitch bends and vibrato
  • Works with various instruments, not just piano
  • Is lightweight and open-source

More about BasicPitch:


Steps to Convert MP3 to MIDI

1. Install Dependencies

First, install the required Python packages:


pip install basic-pitch ffmpeg-python


2. Use This Python Script

This script will process the MP3 file, run BasicPitch’s AI model, and save the MIDI file.

import os
from basic_pitch.inference import predict_and_save from basic_pitch import ICASSP_2022_MODEL_PATH # -------------------------------------- # MP3 to MIDI Conversion using BasicPitch by Spotify # This script processes an MP3 file using BasicPitch # and saves the resulting MIDI file in the output directory. # -------------------------------------- # Define the input MP3 file path (Replace "song.mp3" with your actual file) input_mp3 = r"song.mp3" # Ensure the file is in the same directory or provide a full path # Define the output directory where MIDI files will be saved output_dir = r"output" # Check if the input MP3 file exists before proceeding if not os.path.exists(input_mp3): raise FileNotFoundError(f"Error: The file '{input_mp3}' does not exist. Please check the path.") # Load the BasicPitch model basic_pitch_model = str(ICASSP_2022_MODEL_PATH) # -------------------------------------- # Running the BasicPitch Inference Model # The model will analyze the MP3 file and generate a MIDI file. # -------------------------------------- print("Running BasicPitch inference on the MP3 file...") predict_and_save( [input_mp3], # Use MP3 directly, no need to convert to WAV manually output_dir, # Save MIDI files in the output directory save_midi=True, # Enable saving the MIDI output sonify_midi=False, # Disable MIDI sonification (audio rendering) save_model_outputs=False, # Disable saving raw model outputs save_notes=False, # Disable saving individual note files model_or_model_path=basic_pitch_model, # Load BasicPitch model ) # MIDI conversion complete. Check the output folder. print(f"Conversion complete. Check the '{output_dir}' folder for the MIDI files.")

Setup Instructions

Why Use BasicPitch Instead of Other MIDI Conversion Tools?

Feature      BasicPitch (Spotify)Other Tools
AI-powered      Yes               Mostly rule-based
Polyphonic (Multiple Notes)      Yes               Mostly monophonic
Pitch Bends and Vibrato      Yes               No or limited
Open Source      Yes               Often paid
Lightweight and Fast      Yes               Some require heavy processing

Real-World Use Cases

  • Convert guitar recordings to MIDI for editing in DAWs like Ableton and FL Studio
  • Transcribe piano melodies into MIDI for remixing or re-orchestrating
  • Turn vocal hums into music notes to create melodies from scratch
  • Use for music education and research to analyze complex musical pieces

What’s Next?

Once your MP3 is converted to MIDI, you can:

  • Import it into DAWs like Ableton, FL Studio, Logic Pro, or GarageBand
  • Assign virtual instruments to the MIDI notes and create new sounds
  • Use it for sheet music transcription and study compositions

Have you tried BasicPitch yet? What are your thoughts? Let me know in the comments.


Useful Resources

Thursday, January 9, 2025

How to Use OWASP Dependency Check in a Maven Project

OWASP Dependency Check is a software composition analysis (SCA) tool that scans your project's dependencies for known vulnerabilities. It cross-references dependencies with databases like the National Vulnerability Database (NVD) to help you proactively identify and mitigate risks in third-party libraries. This guide explains how to integrate and use OWASP Dependency Check in a Maven project.


What is OWASP Dependency Check?

OWASP Dependency Check is an open-source tool that:

  • Identifies vulnerabilities in project dependencies by referencing public vulnerability databases.
  • Helps mitigate risks by providing CVE details, severity levels, and suggested fixes.
  • Integrates seamlessly with Maven, Gradle, CI/CD pipelines, and other build tools.

Step 1: Add Dependency Check Plugin to Maven

To integrate Dependency Check with Maven, add the plugin configuration to your pom.xml:

<build>
<plugins> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>8.4.0</version> <!-- Use the latest version --> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

Step 2: Run the Dependency Check

Execute the following Maven command to start the vulnerability scan:

mvn dependency-check:check

Use mvn dependency-check:update-only on subsequent runs to reduce execution time.

What Happens:

  • The plugin scans your project's dependencies, fetches data from the NVD, and identifies vulnerabilities.
  • Reports are generated in the target directory:
    • HTML Report: dependency-check-report.html
    • JSON Report: dependency-check-report.json

Step 3: Review the Results

  1. Access the Reports:

    • Navigate to the target directory to view the generated reports.
    • Open dependency-check-report.html for a detailed summary.
  2. Understand the Output:

    • Each dependency is checked for known CVEs.
    • Severity is indicated using the CVSS (Common Vulnerability Scoring System).
  3. Take Action:

    • Update vulnerable dependencies to patched versions.
    • Exclude unused or unnecessary dependencies.

Step 4: Configure Dependency Check

Customize the plugin behavior to suit your project needs. Use the <configuration> tag in pom.xml for advanced settings.

Example Configuration:

<plugin>
<groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>8.4.0</version> <configuration> <outputDirectory>./dependency-check-reports</outputDirectory> <formats> <format>HTML</format> <format>JSON</format> </formats> <failBuildOnCVSS>7</failBuildOnCVSS> <!-- Fail build for CVSS >= 7 --> <nvd.api.key>your-nvd-api-key</nvd.api.key> <!-- Optional NVD API Key --> </configuration> </plugin>

Step 5: Enhance Performance with NVD API Key

The NVD API key helps:

  • Improve scan reliability by increasing request limits to the NVD database.
  • Reduce delays caused by throttling during frequent scans.

How to Use the API Key:

  1. Obtain an API Key:
  2. Configure the API Key:
    • Add it to your pom.xml:
      <configuration>
      <nvd.api.key>your-nvd-api-key</nvd.api.key> </configuration>
    • Or pass it via the command line:
      mvn dependency-check:check -Dnvd.api.key=your-nvd-api-key
    • Or set it as an environment variable:
      export NVD_API_KEY=your-nvd-api-key

Step 6: Automate with CI/CD

Integrate OWASP Dependency Check into your CI/CD pipeline to ensure continuous security validation.

GitHub Actions Example:

name: Dependency Check
on: push: branches: - main jobs: dependency-check: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Set up Java uses: actions/setup-java@v3 with: java-version: 11 - name: OWASP Dependency Check run: mvn dependency-check:check

Common Issues and Solutions

  1. Slow Scans:

    • Use an NVD API key for faster updates.
    • Run mvn dependency-check:update-only to pre-cache vulnerability data.
  2. False Positives:

    • Exclude specific dependencies:
      <configuration>
      <excludes> <exclude>com.example:example-dependency</exclude> </excludes> </configuration>
  3. Large Projects:

    • Adjust database refresh intervals:
      <cveValidForHours>72</cveValidForHours>

Tips for Best Practices

  1. Update Regularly:
    • Ensure the plugin and NVD database are up-to-date.
  2. Fail Builds on High-Risk Vulnerabilities:
    • Use <failBuildOnCVSS> to enforce a security threshold.
  3. Exclude Dev-Only Dependencies:
    • Use <scope>test</scope> for test dependencies that don’t need production scans.

Conclusion

OWASP Dependency Check is a vital tool for identifying and mitigating risks in your project's dependencies. By integrating it into your Maven project and CI/CD pipelines, you can proactively manage vulnerabilities and ensure compliance with security standards.

Wednesday, December 18, 2024

Debugging Azure Face API Errors with Python: Handling InvalidRequest

Introduction

While working with the Azure Face API to implement headshot validation, I encountered the following error during a face detection task:

Error during API call: (InvalidRequest) Invalid request has been sent.

This generic error provided no actionable information, making debugging difficult. To resolve the issue, I had to:

  • Dig deeper into the FaceClient SDK.
  • Enable logging to capture HTTP requests and responses.
  • Eventually uncover the root cause: the returnFaceId parameter.

This post will walk you through:

  1. How I identified and resolved the issue.
  2. Why the returnFaceId parameter caused the error.
  3. How to fix and debug similar issues in the Azure Face API.
  4. How to request approval for the returnFaceId feature.
  5. How to directly invoke the API for maximum control.

If you’re interested in headshot validation, check out my earlier post: Headshot Validation Using Azure Face API with Python.

Initial Code

Here’s the initial code I was using for face detection:

try:
with open(image_path, "rb") as image_stream:
print("Sending image to Azure Face API...")
detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03" # Modern detection model
)
except Exception as e:
print(f"Error during API call: {e}")
return False

The output:

Error during API call: (InvalidRequest) Invalid request has been sent.

This generic message made it hard to debug the issue. I had no idea whether the problem was with my parameters, the image, or the API itself.

Adding Logging to Debug

To get more details, I enabled HTTP logging to capture the raw request and response sent to the Azure Face API. Here’s the updated code:

import logging

logging.basicConfig(level=logging.DEBUG) # Enable detailed logging

try:
with open(image_path, "rb") as image_stream:
print("Sending image to Azure Face API...")
detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03" # Modern detection model
)
except Exception as e:
if hasattr(e, 'response') and e.response is not None:
print("Error during API call:")
print(f"HTTP Status Code: {e.response.status_code}")
print(f"Response Body: {e.response.text}")
else:
print(f"Error: {e}")
return False

The logs provided invaluable insights into the API behavior:

DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): xxxx.cognitiveservices.azure.com:443
DEBUG:urllib3.connectionpool:https://xxxx.cognitiveservices.azure.com:443 "POST /face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&recognitionModel=recognition_01&returnRecognitionModel=false&detectionModel=detection_03&faceIdTimeToLive=86400 HTTP/11" 403 362
DEBUG:msrest.exceptions:(InvalidRequest) Invalid request has been sent.
Error during API call:
HTTP Status Code: 403
Response Body: {
"
error": {
"
code": "InvalidRequest",
"
message": "Invalid request has been sent.",
"
innererror": {
"
code": "UnsupportedFeature",
"
message": "Feature is not supported, missing approval for one or more of the following features: Identification,Verification. Please apply for access at https://aka.ms/facerecognition"
}
}
}

Root Cause: returnFaceId Defaults to True


The returnFaceId parameter in the Azure FaceClient SDK defaults to True, meaning the API tries to generate and return a unique Face ID for each detected face. This Face ID serves as a temporary identifier for the detected face, enabling workflows like face recognition, verification, and finding similar faces. The Face ID represents the face’s extracted features and can be used in subsequent API calls to match or compare faces.

 However:

  • This feature is restricted to approved customers only.
  • If you don’t have approval, the API rejects the request with an InvalidRequest error.

Since my application only required face detection (and not recognition tasks), I resolved the issue by explicitly setting return_face_id=False:

detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03",
return_face_id=False # Explicitly exclude Face ID
)

Directly Invoking the Azure Face API

If you prefer full control over your API parameters, you can bypass the SDK and call the Azure Face API directly. This avoids SDK defaults like returnFaceId=True.

Using cURL

curl -X POST "https://your-endpoint.cognitiveservices.azure.com/face/v1.0/detect" \
-H "Content-Type: application/octet-stream" \
-H "Ocp-Apim-Subscription-Key: your_subscription_key" \
--data-binary "@your_image.jpg"

Using Python requests

import requests
FACE_API_KEY = "your_subscription_key"
FACE_API_ENDPOINT = "https://your-endpoint.cognitiveservices.azure.com/face/v1.0/detect"
headers = {
"Content-Type": "application/octet-stream",
"Ocp-Apim-Subscription-Key": FACE_API_KEY
}
params = {
"detectionModel": "detection_03"
}
with open("your_image.jpg", "rb") as image_stream:
response
= requests.post(FACE_API_ENDPOINT, headers=headers, params=params, data=image_stream)
print(response.json())

Direct API calls allow you to explicitly include or exclude parameters, ensuring greater flexibility.

How to Fix returnFaceId Errors

Set return_face_id=False:

  • Unless your application requires face recognition workflows, explicitly exclude Face IDs:
detected_faces = face_client.face.detect_with_stream(
image=image_stream,
detection_model="detection_03",
return_face_id=False
)

Request Approval for returnFaceId:

Best Practices for Debugging Azure Face API

Enable Logging:

  • Use Python’s logging module to capture HTTP requests and responses:
import logging
logging.basicConfig(level=logging.DEBUG)

Check API Documentation:

Use cURL for Simple Tests:

  • Test the API using cURL to isolate issues before implementing in Python.

Handle API Exceptions Gracefully:

  • Extract and print detailed responses from exceptions:
if hasattr(e, 'response') and e.response is not None:
print(f"HTTP Status Code: {e.response.status_code}")
print(f"Response Body: {e.response.text}")

Conclusion

The returnFaceId parameter is powerful for face recognition workflows but requires approval for use. If you don’t need face IDs, explicitly set return_face_id=False to avoid errors. For advanced use cases requiring face IDs, submit a request for access.

By adding logging and carefully reviewing the API response, you can effectively debug and resolve issues in the Azure Face API, making it a reliable tool for tasks like headshot validation and face detection.

For a practical implementation of headshot validation, check out my post: Headshot Validation Using Azure Face API.

Wednesday, November 20, 2024

How to Configure a Reverse Proxy on Windows Using NGINX

A reverse proxy acts as an intermediary server between clients and backend servers, forwarding requests and responses. Using NGINX as a reverse proxy enhances performance, strengthens security, simplifies application routing, and facilitates session sharing.

Refer to the following posts to understand more about the reverse proxy - Apache Reverse Proxy: Content From Different Websites | by Albin Issac | The Startup | Medium

Implementing Cross-Domain Cookie Handling for Seamless API Integration | by Albin Issac | Tech Learnings | Medium



Steps to Set Up NGINX as a Reverse Proxy on Windows:

 Install NGINX:

       
start nginx      
 

Configure Reverse Proxy:

  • Open the nginx.conf file in C:\nginx\conf\nginx.conf
Add the reverse proxy configuration: Here is the minimal configuration to proxy the requests to the backend server. You can add multiple servers and locations.

           
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}



http {
    include       mime.types;
    default_type  application/octet-stream;
	
	log_format upstream_logging '[$time_local] $remote_addr - $remote_user - $server_name '
                                 'to: $upstream_addr: $request '
                                 'status $status upstream_response_time $upstream_response_time '
                                 'request_time $request_time '
                                 'headers: "$http_user_agent, 
                                 $http_x_forwarded_for, $http_x_cip_client_id" '
                                 'upstream_headers: "$upstream_http_content_type, 
                                 $upstream_http_content_length"';

    sendfile        on;

    keepalive_timeout  65;
	
	
	

server {
    listen 8000;
    listen [::]:8000;
	
    #SSL Support
    #listen 8000 ssl;
    #listen [::]:8000 ssl;

    server_name localhost;
	
    #Debug Logging
    #error_log logs/error.log debug;
	
    access_log logs/api_logging.log upstream_logging;
	
    #Configurations to support SSL
	
    #ssl_certificate      C://cert/localhost.crt;
    #ssl_certificate_key  C://cert/localhost.key;

    #ssl_session_cache    shared:SSL:1m;
    #ssl_session_timeout  5m;

    #ssl_ciphers  HIGH:!aNULL:!MD5;
    #ssl_prefer_server_ciphers  on;

    proxy_buffering off;
    proxy_busy_buffers_size   512k;
    proxy_buffers   4 512k;
    proxy_buffer_size   256k;	
	
	location / {
            root   html;
            index  index.html index.htm;
    }


    location /test/api {
		proxy_pass https://api.server.com;   

		proxy_set_header Host $proxy_host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header Header1  Header1 value;
                proxy_set_header Header2  Header2 value;
		proxy_ssl_name   $proxy_host;    
		proxy_ssl_server_name on; 
		
		#Set the Response Header with backend response headers for debugging
		
		#add_header X-Backend-Status $upstream_status;
		#add_header X-Backend-Server $upstream_addr;
		#add_header X-Backend-Content-Type $upstream_http_content_type;
		#add_header X-Backend-Content-Length $upstream_http_content_length;
		
		proxy_connect_timeout 60s;       # Timeout for connecting to the upstream
		proxy_send_timeout 60s;          # Timeout for sending to the upstream
		proxy_read_timeout 60s;          # Timeout for reading from the upstream


    }
}

   
}


       
 

Save the file and reload NGINX: 

       
 nginx -s reload
       
 

Test the Setup:

Access the API in your browser through localhost e.g http://localhost:8000/test/api/getOrder in your browser. It should forward requests to your backend server and return the response.

Stop NGINX server
 
       
 nginx -s stop      
 
Additionally, you can 

  • Enable HTTPS: Secure the proxy with SSL certificates.
  • Load Balancing: Add multiple backend servers:

  • Using NGINX as a reverse proxy on Windows is a powerful way to manage and secure web traffic.
    With a few simple steps, you can enable features like load balancing, SSL termination, and caching, making your application more robust and scalable.