ANTIGRAVITY LABJP
Articles/Integrations
Integrations/2026-03-10Intermediate

Suno AI × Antigravity Sound Generation — Add Music to Your Apps with AI

Learn how to integrate Suno AI's music generation capabilities with Antigravity to create original BGM and sound effects for your applications.

Suno AI2Music GenerationSound DesignAudio IntegrationCreative Tools

Setup and context

In modern application development, high-quality sound design is a significant competitive advantage. However, creating professional music and sound effects traditionally requires hiring audio engineers or composers—a time-consuming and expensive process.

Suno AI is an AI-powered service that generates realistic music from text descriptions, and when combined with Antigravity, it dramatically streamlines your audio production workflow. This guide walks you through integrating Suno AI with Antigravity, from setup to real-world implementation in web and mobile applications.

What Is Suno AI?

Overview and Capabilities

Suno AI is an AI platform that generates high-quality music from text prompts. Key features include:

  • Text-to-Music Generation: Create complete compositions from descriptive prompts
  • Multi-Genre Support: Generate rock, pop, classical, ambient, EDM, and many other styles
  • Fine-Grained Control: Specify instruments, tempo, vocal style, and other parameters
  • API Access: Programmatic integration for automated workflows

Why Antigravity Enhances the Workflow

Antigravity's AI assistance capabilities enable:

  • Automatic prompt generation for Suno AI from natural language descriptions
  • Batch music generation workflow automation
  • Metadata organization and management of generated audio assets
  • Intelligent code generation for API integration

Getting Started with Suno AI

Account Setup

# 1. Sign up for Suno AI
# Visit https://www.suno.ai and create an account
 
# 2. Generate your API key
# Navigate to Dashboard > Settings > API Keys and copy your key
 
# 3. Store in environment variables
export SUNO_API_KEY="your_api_key_here"

Configuring Antigravity for Audio Generation

Craft your system prompt to optimize audio generation:

You are an expert in music and sound design for applications.
Your role is to generate high-quality BGM and sound effects.

When given application requirements:
- Specify genre, tempo, and mood clearly
- Include technical specifications (sample rate, duration)
- Consider licensing and commercial use requirements
- Format requests for the Suno API

Generating Background Music (BGM)

Strategy for Game Applications

Generate BGM for adventure game "Escape Chronicles"
 
Specifications:
- Genre: Epic Adventure Ambient
- Tempo: 120 BPM
- Duration: 3-minute loopable track
- Instruments: Synthesizers, Percussion
- Vocals: None
- Atmosphere: Mysterious and exciting
 
Suno Prompt:
"Epic adventure ambient track with mysterious synth layers,
tribal percussion elements, building tension, 120 BPM,
loopable 3-minute composition"

Creating Loopable BGM for Productivity Apps

// Generate seamless loop for focus/productivity app
const bgmRequest = {
  prompt: "Calm, minimalist ambient background music suitable for focus apps. Soft piano with subtle string pads. 60 BPM, 2-minute loopable composition",
  model: "chirp-v3",
  duration: 120,
  loop: true,
  style_preset: "ambient"
};
 
// Execute generation
async function generateFocusBGM(request) {
  const response = await fetch('https://api.suno.ai/v1/generate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SUNO_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(request)
  });
 
  const result = await response.json();
  return result.audio_url;
}

Creating Sound Effects (SFX)

Effective SFX Prompt Design

Sound effects perform best with concise, specific prompts:

Sound Effect: Button Click
 
Requirements:
- Type: Digital notification ping
- Duration: 500ms
- Frequency: Bright, high-pitched
- Character: Crisp and responsive
 
Suno Prompt:
"Bright digital ping sound effect for UI button click,
500ms duration, high frequency, crisp and clear response"

Sound Effect Manager Implementation

class SoundEffectManager {
  constructor() {
    this.sfxCache = new Map();
  }
 
  async generateSFX(sfxName, prompt) {
    // Check cache first
    if (this.sfxCache.has(sfxName)) {
      return this.sfxCache.get(sfxName);
    }
 
    const response = await fetch('https://api.suno.ai/v1/generate', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.SUNO_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        prompt: prompt,
        duration: 2,  // Max 2 seconds for SFX
        model: 'chirp-v3'
      })
    });
 
    const result = await response.json();
    this.sfxCache.set(sfxName, result);
 
    return result;
  }
 
  playSFX(sfxName) {
    const sfx = this.sfxCache.get(sfxName);
    if (sfx) {
      const audio = new Audio(sfx.audio_url);
      audio.play();
    }
  }
 
  async preloadAllSFX(sfxDefinitions) {
    const promises = sfxDefinitions.map(def =>
      this.generateSFX(def.name, def.prompt)
    );
    await Promise.all(promises);
  }
}

API Integration and Workflow Automation

Batch Generation with Antigravity

// Use Antigravity to generate comprehensive audio package specification
const batchGenPrompt = `
Generate specifications for a complete mobile game audio package.
For each of the following, create a detailed Suno AI prompt:
 
1. Main Menu BGM - Uplifting, 3 minutes, loopable
2. Level 1 Background - Ambient, 2 minutes, loopable
3. Victory Sound Effect - Celebratory, 2 seconds
4. Game Over Sound Effect - Dramatic, 3 seconds
5. Coin Pickup - Digital jingle, 0.5 seconds
6. Power-up Activation - Energetic whoosh, 1 second
 
Format each as JSON with: name, prompt, duration, type
`;
 
// Process generated prompts through Suno API
async function generateGameAudioPackage(sunoPrompts) {
  const audioAssets = [];
 
  for (const item of sunoPrompts) {
    try {
      const response = await fetch('https://api.suno.ai/v1/generate', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.SUNO_API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          prompt: item.prompt,
          duration: item.duration
        })
      });
 
      const result = await response.json();
      audioAssets.push({
        name: item.name,
        type: item.type,
        url: result.audio_url,
        duration: item.duration,
        generatedAt: new Date().toISOString()
      });
 
      // Respect API rate limits
      await new Promise(resolve => setTimeout(resolve, 1500));
    } catch (error) {
      console.error(`Failed to generate ${item.name}:`, error);
    }
  }
 
  return audioAssets;
}

Asset Metadata Management

class AudioAssetRepository {
  async saveAudioAsset(audioData) {
    const asset = {
      id: crypto.randomUUID(),
      name: audioData.name,
      type: audioData.type,
      duration: audioData.duration,
      url: audioData.url,
      format: 'mp3',
      sampleRate: 48000,
      bitrate: '192kbps',
      license: 'commercial-use-allowed',
      createdAt: new Date().toISOString(),
      checksums: {
        md5: await calculateMD5(audioData.url)
      }
    };
 
    // Store in database
    await database.audioAssets.insert(asset);
    return asset;
  }
 
  async generateAudioManifest(projectId) {
    const assets = await database.audioAssets.find({ projectId });
 
    return {
      projectId,
      version: '1.0',
      totalAssets: assets.length,
      totalDuration: assets.reduce((sum, a) => sum + a.duration, 0),
      assets: assets.map(a => ({
        id: a.id,
        name: a.name,
        type: a.type,
        url: a.url,
        duration: a.duration
      })),
      exportedAt: new Date().toISOString()
    };
  }
}

Licensing and Legal Considerations

Suno AI Terms of Use

  • Commercial Use: Verify that your usage tier permits commercial use
  • Attribution: Check if credit attribution is required in your application
  • Copyright: Clearly document copyright ownership of generated audio
  • Restrictions: Review any geo-restrictions or platform limitations

Pre-Launch Compliance Checklist

## Audio Licensing Compliance
 
- [ ] Verified commercial use rights with Suno AI plan
- [ ] Documented attribution requirements (if any)
- [ ] Recorded copyright holder information
- [ ] Added license notices to app documentation/settings
- [ ] Reviewed platform-specific audio requirements
- [ ] Established update schedule for audio licenses
- [ ] Tested audio playback on target devices
- [ ] Created fallback audio for license expiration scenarios

Web Application Implementation

React Integration Example

import { useState, useCallback } from 'react';
 
function AudioGeneratorWidget({ appType }) {
  const [audioUrl, setAudioUrl] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
 
  const generateAudio = useCallback(async () => {
    setIsLoading(true);
    setError(null);
 
    try {
      // Call Antigravity to generate optimized prompt
      const promptResponse = await fetch('/api/audio-prompts', {
        method: 'POST',
        body: JSON.stringify({ appType, purpose: 'bgm' })
      });
 
      if (!promptResponse.ok) throw new Error('Prompt generation failed');
      const { prompt } = await promptResponse.json();
 
      // Call Suno API via backend
      const audioResponse = await fetch('/api/audio/generate', {
        method: 'POST',
        body: JSON.stringify({ prompt })
      });
 
      if (!audioResponse.ok) throw new Error('Audio generation failed');
      const { audioUrl: url } = await audioResponse.json();
 
      setAudioUrl(url);
    } catch (err) {
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  }, [appType]);
 
  return (
    <div className="audio-generator">
      <button
        onClick={generateAudio}
        disabled={isLoading}
        className="btn btn-primary"
      >
        {isLoading ? 'Generating Audio...' : 'Generate BGM'}
      </button>
 
      {error && (
        <div className="alert alert-error">{error}</div>
      )}
 
      {audioUrl && (
        <div className="audio-player">
          <audio controls controlsList="nodownload">
            <source src={audioUrl} type="audio/mpeg" />
            Your browser does not support the audio element.
          </audio>
        </div>
      )}
    </div>
  );
}
 
export default AudioGeneratorWidget;

Backend API Implementation

// api/audio/generate.js
import { Suno } from '@suno/sdk';
 
const suno = new Suno({
  apiKey: process.env.SUNO_API_KEY
});
 
export async function POST(request) {
  const { prompt } = await request.json();
 
  if (!prompt) {
    return new Response(
      JSON.stringify({ error: 'Prompt is required' }),
      { status: 400 }
    );
  }
 
  try {
    const generation = await suno.generate({
      prompt,
      model: 'chirp-v3',
      make_instrumental: false
    });
 
    // Poll for completion
    let result = generation;
    let attempts = 0;
    const maxAttempts = 30;
 
    while (result.status === 'pending' && attempts < maxAttempts) {
      await new Promise(resolve => setTimeout(resolve, 2000));
      result = await suno.getGeneration(generation.id);
      attempts++;
    }
 
    if (result.status !== 'completed') {
      throw new Error('Audio generation did not complete in time');
    }
 
    return new Response(
      JSON.stringify({
        audioUrl: result.audio_url,
        duration: result.duration,
        generatedAt: new Date().toISOString()
      }),
      { status: 200, headers: { 'Content-Type': 'application/json' } }
    );
  } catch (error) {
    console.error('Audio generation error:', error);
    return new Response(
      JSON.stringify({ error: error.message }),
      { status: 500 }
    );
  }
}

Mobile Application Implementation

iOS with SwiftUI

import AVFoundation
import Combine
 
class AudioService: NSObject, ObservableObject {
    @Published var isPlaying = false
    @Published var currentAudioUrl: URL?
    @Published var isGenerating = false
 
    private var audioPlayer: AVAudioPlayer?
 
    func generateAndPlayBGM(for appType: String) async {
        DispatchQueue.main.async {
            self.isGenerating = true
        }
 
        do {
            // Generate prompt via Antigravity
            let promptRequest = URLRequest(
                url: URL(string: "https://api.antigravity.app/audio-prompts")!
            )
 
            // Call Suno API
            let audioUrl = try await fetchGeneratedAudio(for: appType)
 
            // Play generated audio
            playAudio(from: audioUrl)
 
            DispatchQueue.main.async {
                self.currentAudioUrl = audioUrl
                self.isGenerating = false
            }
        } catch {
            print("Audio generation error: \(error)")
            DispatchQueue.main.async {
                self.isGenerating = false
            }
        }
    }
 
    private func playAudio(from url: URL) {
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback)
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            audioPlayer?.play()
            isPlaying = true
        } catch {
            print("Playback error: \(error)")
        }
    }
 
    private func fetchGeneratedAudio(for appType: String) async throws -> URL {
        // Implementation to fetch from Suno API
        fatalError("Implement Suno API call")
    }
 
    func stopPlayback() {
        audioPlayer?.stop()
        isPlaying = false
    }
}
 
struct AudioPlayerView: View {
    @StateObject private var audioService = AudioService()
    let appType: String
 
    var body: some View {
        VStack(spacing: 20) {
            if audioService.isGenerating {
                ProgressView("Generating audio...")
            } else {
                Button(action: {
                    Task {
                        await audioService.generateAndPlayBGM(for: appType)
                    }
                }) {
                    Label("Generate BGM", systemImage: "waveform")
                }
                .disabled(audioService.isGenerating)
            }
 
            if let url = audioService.currentAudioUrl {
                HStack {
                    Button(action: {
                        audioService.stopPlayback()
                    }) {
                        Image(systemName: audioService.isPlaying ? "stop.fill" : "play.fill")
                    }
 
                    Text(audioService.isPlaying ? "Playing..." : "Paused")
                        .foregroundColor(.secondary)
                }
            }
        }
        .padding()
    }
}

Android with Kotlin

import android.media.MediaPlayer
import kotlinx.coroutines.launch
 
class AudioViewModel : ViewModel() {
    private val _isPlaying = MutableLiveData<Boolean>(false)
    val isPlaying: LiveData<Boolean> = _isPlaying
 
    private val _isGenerating = MutableLiveData<Boolean>(false)
    val isGenerating: LiveData<Boolean> = _isGenerating
 
    private var mediaPlayer: MediaPlayer? = null
 
    fun generateAndPlayBGM(appType: String) {
        viewModelScope.launch {
            _isGenerating.value = true
 
            try {
                // Generate prompt via Antigravity
                val prompt = generateAudioPrompt(appType)
 
                // Get audio from Suno API
                val audioUrl = generateSunoAudio(prompt)
 
                // Play audio
                playAudio(audioUrl)
 
                _isGenerating.value = false
            } catch (e: Exception) {
                Log.e("AudioViewModel", "Generation failed", e)
                _isGenerating.value = false
            }
        }
    }
 
    private fun playAudio(audioUrl: String) {
        mediaPlayer?.release()
 
        mediaPlayer = MediaPlayer().apply {
            setDataSource(audioUrl)
            prepareAsync()
            setOnPreparedListener { mp ->
                mp.start()
                _isPlaying.value = true
            }
            setOnCompletionListener {
                _isPlaying.value = false
            }
        }
    }
 
    private suspend fun generateSunoAudio(prompt: String): String {
        return withContext(Dispatchers.IO) {
            // Implementation to call Suno API
            ""
        }
    }
 
    fun stopPlayback() {
        mediaPlayer?.stop()
        mediaPlayer?.release()
        mediaPlayer = null
        _isPlaying.value = false
    }
 
    override fun onCleared() {
        mediaPlayer?.release()
        super.onCleared()
    }
}

Troubleshooting and Optimization

Handling API Rate Limits

class RateLimitManager {
  constructor(requestsPerMinute = 10) {
    this.maxRequests = requestsPerMinute;
    this.requestQueue = [];
    this.processing = false;
  }
 
  async executeWithRateLimit(fn) {
    return new Promise((resolve, reject) => {
      this.requestQueue.push({ fn, resolve, reject });
      this.processQueue();
    });
  }
 
  private async processQueue() {
    if (this.processing || this.requestQueue.length === 0) {
      return;
    }
 
    this.processing = true;
    const now = Date.now();
    const oneMinuteAgo = now - 60000;
 
    // Remove old timestamps
    this.requestTimestamps = this.requestTimestamps.filter(
      ts => ts > oneMinuteAgo
    );
 
    // Check if we can process next request
    if (this.requestTimestamps.length < this.maxRequests) {
      const { fn, resolve, reject } = this.requestQueue.shift();
 
      try {
        const result = await fn();
        this.requestTimestamps.push(now);
        resolve(result);
      } catch (error) {
        reject(error);
      }
 
      this.processing = false;
      this.processQueue();
    } else {
      // Wait before processing next request
      const waitTime = 60000 - (now - this.requestTimestamps[0]);
      setTimeout(() => {
        this.processing = false;
        this.processQueue();
      }, waitTime);
    }
  }
}

Audio Quality Best Practices

  • Format: MP3 (128-320 kbps) or WAV for lossless
  • Sample Rate: 44.1 kHz or 48 kHz
  • Bit Depth: 16-bit minimum, 24-bit for high fidelity
  • Mono vs Stereo: Stereo for music, mono acceptable for SFX

Performance Optimization

class OptimizedAudioCache {
  constructor(maxSize = 100) {
    this.cache = new Map();
    this.maxSize = maxSize;
  }
 
  async getOrGenerate(key, generator) {
    if (this.cache.has(key)) {
      return this.cache.get(key);
    }
 
    const result = await generator();
 
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
 
    this.cache.set(key, result);
    return result;
  }
 
  prefetch(keys, generator) {
    return Promise.all(
      keys.map(key => this.getOrGenerate(key, () => generator(key)))
    );
  }
}

Conclusion

The combination of Suno AI and Antigravity transforms audio production for your applications:

  • Speed: Generate professional-quality music in seconds
  • Customization: Fine-grained control through natural language prompts
  • Cost Efficiency: Eliminate expensive audio production workflows
  • Scalability: Seamlessly integrate across multiple projects via API

By mastering prompt design, managing licenses responsibly, and optimizing API usage, you can add sophisticated audio experiences to any application—all without requiring specialized audio expertise.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Integrations2026-07-11
Nobody Is There to Say Yes: Writing Unified Permissions as an Unattended Contract
The v2.2.1 unified permission system assumes a person is watching. On a 3 a.m. scheduled run, that assumption quietly breaks. Here is how I declared the policy up front as an allow / deny / queue contract so an unattended agent never stalls on a prompt no one can answer.
Integrations2026-07-09
Calling Local LLMs from Antigravity — Ollama and LM Studio Integration in Practice
Treating Antigravity as a cloud-LLM-only tool? Pairing it with Ollama or LM Studio opens up real options for confidential projects and cost-sensitive workloads. Here's the practical configuration and operational knowledge.
Integrations2026-07-08
Antigravity Now Saves OAuth Tokens to the OS Keyring — Keeping Auth Alive in Headless Runs
In v2.2.1, refreshed OAuth tokens are saved to the OS keyring automatically. Pleasant on the desktop, but on headless scheduled runs the vault itself may not exist and auth quietly breaks. We design explicit backend selection, a safe file fallback, and per-location liveness checks.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →