[GO] Je veux créer un lecteur de musique et enregistrer de la musique en même temps

La dernière fois, j'ai pu jouer de la musique avec Go https://qiita.com/usk81/items/8590172a23bb71e21329

J'ouvre généralement deux onglets de navigateur avec Nico Dou et joue la même chanson en même temps avec différents chanteurs et joue un duo, alors j'ai pensé que je pourrais le faire avec un programme.

Code d'origine

// package main plays two audio file
package main

import (
    "log"
    "os"
    "time"

    "github.com/faiface/beep"
    "github.com/faiface/beep/mp3"
    "github.com/faiface/beep/speaker"
)

func main() {
    f, err := os.Open("test.mp3")
    if err != nil {
        log.Fatal(err)
    }
    st, format, err := mp3.Decode(f)
    if err != nil {
        log.Fatal(err)
    }
    defer st.Close()

    speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))

    done := make(chan bool)
    speaker.Play(beep.Seq(st, beep.Callback(func() {
        done <- true
    })))
    <-done
}

Examiner le code du haut-parleur

// Package speaker implements playback of beep.Streamer values through physical speakers.
package speaker

import (
	"sync"

	"github.com/faiface/beep"
	"github.com/hajimehoshi/oto"
	"github.com/pkg/errors"
)

var (
	mu      sync.Mutex
	mixer   beep.Mixer
	samples [][2]float64
	buf     []byte
	context *oto.Context
	player  *oto.Player
	done    chan struct{}
)

// Init initializes audio playback through speaker. Must be called before using this package.
//
// The bufferSize argument specifies the number of samples of the speaker's buffer. Bigger
// bufferSize means lower CPU usage and more reliable playback. Lower bufferSize means better
// responsiveness and less delay.
func Init(sampleRate beep.SampleRate, bufferSize int) error {
	mu.Lock()
	defer mu.Unlock()

	Close()

	mixer = beep.Mixer{}

	numBytes := bufferSize * 4
	samples = make([][2]float64, bufferSize)
	buf = make([]byte, numBytes)

	var err error
	context, err = oto.NewContext(int(sampleRate), 2, 2, numBytes)
	if err != nil {
		return errors.Wrap(err, "failed to initialize speaker")
	}
	player = context.NewPlayer()

	done = make(chan struct{})

	go func() {
		for {
			select {
			default:
				update()
			case <-done:
				return
			}
		}
	}()

	return nil
}

// Close closes the playback and the driver. In most cases, there is certainly no need to call Close
// even when the program doesn't play anymore, because in properly set systems, the default mixer
// handles multiple concurrent processes. It's only when the default device is not a virtual but hardware
// device, that you'll probably want to manually manage the device from your application.
func Close() {
	if player != nil {
		if done != nil {
			done <- struct{}{}
			done = nil
		}
		player.Close()
		context.Close()
		player = nil
	}
}

// Lock locks the speaker. While locked, speaker won't pull new data from the playing Stramers. Lock
// if you want to modify any currently playing Streamers to avoid race conditions.
//
// Always lock speaker for as little time as possible, to avoid playback glitches.
func Lock() {
	mu.Lock()
}

// Unlock unlocks the speaker. Call after modifying any currently playing Streamer.
func Unlock() {
	mu.Unlock()
}

// Play starts playing all provided Streamers through the speaker.
func Play(s ...beep.Streamer) {
	mu.Lock()
	mixer.Add(s...)
	mu.Unlock()
}

// Clear removes all currently playing Streamers from the speaker.
func Clear() {
	mu.Lock()
	mixer.Clear()
	mu.Unlock()
}

// update pulls new data from the playing Streamers and sends it to the speaker. Blocks until the
// data is sent and started playing.
func update() {
	mu.Lock()
	mixer.Stream(samples)
	mu.Unlock()

	for i := range samples {
		for c := range samples[i] {
			val := samples[i][c]
			if val < -1 {
				val = -1
			}
			if val > +1 {
				val = +1
			}
			valInt16 := int16(val * (1<<15 - 1))
			low := byte(valInt16)
			high := byte(valInt16 >> 8)
			buf[i*4+c*2+0] = low
			buf[i*4+c*2+1] = high
		}
	}

	player.Write(buf)
}

cette?

var (
	mu      sync.Mutex
	mixer   beep.Mixer
	samples [][2]float64
	buf     []byte
	context *oto.Context
	player  *oto.Player
	done    chan struct{}
)

N'est-ce pas juste une question de structure et de méthode?

Essayez de créer une version modifiée

package speaker

import (
	"log"
	"sync"

	"github.com/faiface/beep"
	"github.com/hajimehoshi/oto"
	"github.com/pkg/errors"
)

type Player struct {
	mu      sync.Mutex
	mixer   beep.Mixer
	samples [][2]float64
	buf     []byte
	context *oto.Context
	player  *oto.Player
	done    chan struct{}
}

// Init initializes audio playback through speaker. Must be called before using this package.
//
// The bufferSize argument specifies the number of samples of the speaker's buffer. Bigger
// bufferSize means lower CPU usage and more reliable playback. Lower bufferSize means better
// responsiveness and less delay.
func Init(sampleRate beep.SampleRate, bufferSize int) (p *Player, err error) {
	p = &Player{}
	p.mu.Lock()
	defer p.mu.Unlock()

	p.Close()

	p.mixer = beep.Mixer{}

	numBytes := bufferSize * 4
	p.samples = make([][2]float64, bufferSize)
	p.buf = make([]byte, numBytes)

	p.context, err = oto.NewContext(int(sampleRate), 2, 2, numBytes)
	if err != nil {
		return nil, errors.Wrap(err, "failed to initialize speaker")
	}
	log.Print("before NewPlayer")
	p.player = p.context.NewPlayer()
	log.Print("before NewPlayer")

	p.done = make(chan struct{})
	log.Print("make channel")

	go func() {
		for {
			select {
			default:
				p.update()
			case <-p.done:
				return
			}
		}
	}()

	return p, nil
}

// Close closes the playback and the driver. In most cases, there is certainly no need to call Close
// even when the program doesn't play anymore, because in properly set systems, the default mixer
// handles multiple concurrent processes. It's only when the default device is not a virtual but hardware
// device, that you'll probably want to manually manage the device from your application.
func (p *Player) Close() {
	if p.player != nil {
		if p.done != nil {
			p.done <- struct{}{}
			p.done = nil
		}
		p.player.Close()
		p.context.Close()
		p.player = nil
	}
}

// Lock locks the speaker. While locked, speaker won't pull new data from the playing Stramers. Lock
// if you want to modify any currently playing Streamers to avoid race conditions.
//
// Always lock speaker for as little time as possible, to avoid playback glitches.
func (p *Player) Lock() {
	p.mu.Lock()
}

// Unlock unlocks the speaker. Call after modifying any currently playing Streamer.
func (p *Player) Unlock() {
	p.mu.Unlock()
}

// Play starts playing all provided Streamers through the speaker.
func (p *Player) Play(s ...beep.Streamer) {
	p.mu.Lock()
	p.mixer.Add(s...)
	p.mu.Unlock()
}

// Clear removes all currently playing Streamers from the speaker.
func (p *Player) Clear() {
	p.mu.Lock()
	p.mixer.Clear()
	p.mu.Unlock()
}

// update pulls new data from the playing Streamers and sends it to the speaker. Blocks until the
// data is sent and started playing.
func (p *Player) update() {
	p.mu.Lock()
	p.mixer.Stream(p.samples)
	p.mu.Unlock()

	// buf := p.buf
	for i := range p.samples {
		for c := range p.samples[i] {
			val := p.samples[i][c]
			if val < -1 {
				val = -1
			}
			if val > +1 {
				val = +1
			}
			valInt16 := int16(val * (1<<15 - 1))
			low := byte(valInt16)
			high := byte(valInt16 >> 8)
			p.buf[i*4+c*2+0] = low
			p.buf[i*4+c*2+1] = high
		}
	}

	p.player.Write(p.buf)
}

J'ai essayé de mettre en œuvre

// package main plays two audio file
//   failure: oto.NewContext can be called only once
package main

import (
	"log"
	"os"
	"time"

	"github.com/faiface/beep"
	"github.com/faiface/beep/mp3"

	"github.com/usk81/til/go-duet-player/speaker"
)

func main() {
	f1, err := os.Open("test1.mp3")
	if err != nil {
		log.Fatal(err)
	}
	st1, format, err := mp3.Decode(f1)
	if err != nil {
		log.Fatal(err)
	}
	defer st1.Close()

	sp1, err := speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
	if err != nil {
		log.Fatal(err)
	}

	done1 := make(chan bool)

	f2, err := os.Open("test2.mp3")
	if err != nil {
		log.Fatal(err)
	}
	st2, format, err := mp3.Decode(f2)
	if err != nil {
		log.Fatal(err)
	}
	defer st2.Close()

	sp2, err := speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
	if err != nil {
		log.Fatal(err)
	}

	done2 := make(chan bool)

	sp1.Play(beep.Seq(st1, beep.Callback(func() {
		done1 <- true
	})))
	sp2.Play(beep.Seq(st2, beep.Callback(func() {
		done2 <- true
	})))
	<-done1
	<-done2
}

Ouais, ça ne marche pas

oto: NewContext can be called only once

Je ne pouvais pas parce que le contexte de ʻoto` dont dépend le bip ne semble pas prendre en charge la concurrence. Cette fois, je fais quelque chose tous les jours, alors je vais abandonner cette couche.

Je l'ai essayé avec Python pour le moment.

from pydub import AudioSegment
from pydub.playback import play

#Load an audio file
audio1 = "test1.mp3"
audio2 = "test2.mp3"

sound1 = AudioSegment.from_mp3(audio1)
sound2 = AudioSegment.from_mp3(audio2)

combined = sound1.overlay(sound2)
play(combined)

Ça bouge! !!

En quelque sorte regrettable ... (`; ω; ´)

Remarques

Il n'est pas possible d'ajuster la position au début du chant, veuillez donc l'ajuster en jouant avec un logiciel d'édition de musique.

Recommended Posts

Je veux créer un lecteur de musique et enregistrer de la musique en même temps
Je souhaite extraire les informations d'étiquette (titre et artiste) d'un fichier de musique (flac, wav).
Je veux créer un Dockerfile pour le moment.
Je veux obtenir des informations de fstab à la destination de la connexion ssh et exécuter la commande
Je souhaite séparer le traitement entre le temps de test et l'environnement de production
Python: je souhaite mesurer proprement le temps de traitement d'une fonction
Je souhaite créer une application Web en utilisant React et Python flask
Je veux faire de matplotlib un thème sombre
Je veux faire un jeu avec Python
Je veux écrire dans un fichier avec Python
Je souhaite recevoir le fichier de configuration et vérifier si le fichier JSON généré par jinja2 est un JSON valide
[Salut Py (Partie 1)] Je veux faire quelque chose pour le moment, alors commencez par fixer un objectif.
L'histoire de l'adresse IPv6 que je souhaite conserver au minimum
Je veux déposer un fichier sur tkinter et obtenir son chemin [Tkinter DnD2]
Je veux écrire un élément dans un fichier avec numpy et le vérifier.
Assurez-vous que le prétraitement au moment de la création du modèle de prédiction et de la prédiction est aligné
Je veux ajouter du silence pendant 1 seconde au début d'un fichier wav
Je veux obtenir le nom du fichier, le numéro de ligne et le nom de la fonction dans Python 3.4
Je veux voir le nom de fichier de DataLoader
Visualisez les données et saisissez la corrélation en même temps
Je veux échantillonner au hasard un fichier avec Python
[Python] Je veux faire d'une liste imbriquée un taple
Je souhaite publier le produit au moindre coût
Je veux remplacer les variables dans le fichier de modèle python et le produire en masse dans un autre fichier
Je souhaite créer une base de données de déjeuners [EP1] Django pour la première fois
Je souhaite créer une base de données de déjeuner [EP1-4] Django pour la première fois
wxPython: dessin simultané d'animation et de dessin graphique
Je veux déplacer le sélénium pour le moment [pour mac]
Je veux créer un éditeur de blog avec l'administrateur de django
Je veux faire une macro de clic avec pyautogui (désir)
Je veux faire une macro de clic avec pyautogui (Outlook)
J'ai essayé d'illustrer le temps et le temps du langage C
J'ai essayé d'afficher l'heure et la météo d'aujourd'hui w
Je veux connaître la nature de Python et pip
Je veux rendre le type de dictionnaire dans la liste unique
Je souhaite mapper le code EDINET et le numéro de valeur
Je veux ajouter un joli complément à input () en python
J'ai essayé de publier automatiquement sur ChatWork au moment du déploiement avec Fabric et ChatWork Api
Comment démarrer le PC à une heure fixe chaque matin et exécuter le programme python
Procédure pour changer le nom de la table et le nom de la colonne du modèle Django en même temps
J'ai essayé la même analyse de données avec kaggle notebook (python) et PowerBI en même temps ①
Je veux voir le graphique en 3D! Je peux réaliser un tel rêve.
Je veux trouver l'intersection d'une courbe de Bézier et d'une ligne droite (méthode de découpage de Bézier)
Je veux faire un changeur de voix en utilisant Python et SPTK en référence à un site célèbre
J'ai essayé de créer une expression régulière de "temps" en utilisant Python
Comment faire une commande pour lire le fichier de paramètres avec pyramide
Je veux créer un système pour éviter d'oublier de serrer la clé 1
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
Gratter et manger des bûches - je veux trouver un bon restaurant! ~ (Travail)
[Introduction] Je veux créer un robot Mastodon avec Python! 【Débutants】
Je veux créer un fichier pip et le refléter dans le menu fixe
Je souhaite créer une liste de paramètres à partir du code CloudFormation (yaml)
Je veux faire de la deuxième ligne le nom de la colonne dans pandas
Pour le moment, je veux convertir n'importe quel fichier avec ffmpeg !!
Parcourir .loc et .iloc en même temps dans pandas DataFrame
Je veux pirater Robomaster S1 ① Vérification de l'enracinement et de la configuration des fichiers
Je veux créer un histogramme et superposer la courbe de distribution normale dessus. édition matplotlib
J'ai essayé de trouver la différence entre A + = B et A = A + B en Python, alors notez
[Twitter] Je veux faire des tweets téléchargés (de mon compte) dans un beau CSV
Je veux clarifier la question de la méthode "__init__" et de l'argument "self" de la classe Python.